Compare commits

..

4406 Commits

Author SHA1 Message Date
Dean f40b6930ff
Merge pull request #4914 from MarcZX100/codex/carry-link-follow-symlink-4026
fix(libkernel_sys): follow symbolic links in link
2026-10-14 17:05:05 +13:00
Dean 00f4b3351b
Merge pull request #3972 from semirkabir/feat/videoout-output-status-vrr
feat(videoout): implement sceVideoOutGetOutputStatusWithVrr
2026-10-14 16:44:42 +13:00
Dean a31043146e
Merge pull request #5367 from MarcZX100/marc/sysctl-leaf-enotdir-5356
fix(libkernel): return ENOTDIR for trailing sysctl leaf components
2026-10-14 16:41:21 +13:00
Dean a1ca1e7bad
Merge pull request #5137 from MarcZX100/codex/request-v21-compat
fix(shader): accept both version 21 request layouts
2026-10-14 16:41:11 +13:00
Dean 21def5c6f8
Merge pull request #5597 from JJenkx/fix/thread-stack-retirement-order
fix(libkernel): retire stack metadata before releasing mappings
2026-10-14 16:41:01 +13:00
ThatsLeo 9828710a38 feat(videoout): implement sceVideoOutGetOutputStatusWithVrr
Writes the 80-byte status described in #2746: the sceVideoOutGetOutputStatus
fields followed by zeros, with the documented codes for a null status and an
unknown handle.

(cherry picked from commit e893efad2d0a7b90243d07bf6669cc9b5f540432)
2026-10-14 16:37:40 +13:00
Dean a14ae8e232
Merge pull request #5186 from p3n1cillin/claude/carry-fioclex
fix(libkernel): handle FIOCLEX and FIONCLEX in ioctl
2026-10-14 16:31:08 +13:00
Dean a5f493f90d
Merge pull request #5152 from dev-mca/test/convert-keycode
test(libSceConvertKeycode): cover sceConvertKeycodeGetImeKeyboardType
2026-10-14 16:06:42 +13:00
Dean f5cda839ec
Merge pull request #4717 from Ondra97/codex/fix-relro-unused-filter
fix(relinker): map standalone RELRO in unused import filtering
2026-10-14 16:05:01 +13:00
Dean e1544df5f2
Merge pull request #4772 from TideOPL/perf/spirv-specialization
perf(shader): index specialization tables by SPIR-V id
2026-10-14 16:04:50 +13:00
Dean f265cd5593
Merge pull request #5234 from AnthonyClemens/fix/agc-integer-tessellation-partitioning
fix(agc): accept integer tessellation partitioning
2026-10-14 15:55:50 +13:00
Dean 970316ae04
Merge pull request #4704 from AlxcBTW/feat/input-mouse-look
feat(input): turn mouse speed into a smooth right-stick tilt
2026-10-14 15:55:08 +13:00
Dean 486420f91a
Merge pull request #4950 from MarcZX100/codex/pr-overlap-compatible-merge-base
fix(tools): use the shared merge base for overlap checks
2026-10-14 15:54:50 +13:00
Dean 60ad9ad47c
Merge pull request #4951 from Ondra97/codex/fix-shared-library-import-audit
fix(tools): audit stubs from shared library sources
2026-10-14 15:54:35 +13:00
Dean fcb30fd977
Merge pull request #5219 from pushkarreddyy/feat/agc-dcb-event-write-address
feat(libSceAgc): ignore address argument on non-sample-dump events in sceAgcDcbEventWrite
2026-10-14 15:54:22 +13:00
Dean a8cb091eba
Merge pull request #4955 from Ondra97/codex/fix-high-refresh-skip-policy
fix(tools): accept skips on displays without 120 Hz
2026-10-14 15:54:20 +13:00
Dean 39bf2b9e9d
Merge pull request #4986 from Ondra97/codex/fix-conventions-raw-literals
fix(conventions): ignore C++ raw literal contents
2026-10-14 15:54:04 +13:00
Dean 0fb2f6c89a
Merge pull request #4988 from babyhuey/feat/scenet-so-error
fix(libSceNet): report SO_ERROR from sceNetGetsockopt
2026-10-14 15:53:49 +13:00
Dean 3e4fe4ce31
Merge pull request #5596 from tibzejoker/port/pr-637-main
fix(libc): track writes to singly mapped direct memory without faults on Windows
2026-10-14 15:53:44 +13:00
Dean 0a56aaaf47
Merge pull request #5284 from MarcZX100/codex/nested-exit-5277
fix(libc): finish exit handlers after nested exit
2026-10-14 15:50:18 +13:00
Dean d1b3aa1372
Merge pull request #5195 from SandstromPL/fix/relinker-sce-code-analysis-extent
fix(relinker): keep code analysis inside the code extent of PS4 executables
2026-10-14 15:49:02 +13:00
Dean a7836b1495
Merge pull request #5094 from bubblegg/fix/savedata-save-size
fix(savedata): report a save's size as the mount that created it gave
2026-10-14 15:47:32 +13:00
Dean aa1927872f
Merge pull request #5197 from AlexOfTheForest/test/relinker-cli-module-and-target-options
test(cli): cover module-dir, sce-module-path and target option errors
2026-10-14 15:46:50 +13:00
Dean 094a34c1ab
Merge pull request #5158 from AaravMehta-07/codex/systemservice-contained-exec
fix(libSceSystemService): contain converted executable paths
2026-10-14 15:45:40 +13:00
Dean 94f96c8e2c
Merge pull request #5255 from Nesyth/fix/libkernel-apr-read-past-eof-v2
fix(libkernel): zero-fill APR reads that reach the end of the file
2026-10-14 15:44:14 +13:00
Dean a21d73733c
Merge pull request #5133 from SandstromPL/fix/savedata-search-other-title
fix(savedata): return no saves for a search with another title's ID
2026-10-14 15:41:58 +13:00
Dean a1e1b4d161
Merge pull request #5262 from NaitikJoshiPro/pr/relinker-executable-tls
feat(relinker): executable TLS relocations (TPOFF64, DTPOFF64, DTPMOD64)
2026-10-14 15:41:31 +13:00
Dean 0defec4386
Merge pull request #5199 from Zenodeon/conversion-diagnostics
fix(relinker): identify failed inputs and invalid dynamic values
2026-10-14 15:39:35 +13:00
Dean c693bd7566
Merge pull request #5190 from NumberGuan/codex/check-lsda-landing-addresses
fix(relinker): reject overflowing LSDA landing pad addresses
2026-10-14 15:39:00 +13:00
Dean 75ceccd5db
Merge pull request #4615 from MiniRML/fix/nid-elf-table-layout
fix(nid): validate ELF table layouts before patching
2026-10-14 15:38:11 +13:00
Dean 622fb542d2
Merge pull request #4764 from nikowolf123/fix/conventions-test-fixtures
fix(conventions): skip library test fixtures in the export checks
2026-10-14 15:37:56 +13:00
Dean 9b6555bd47
Merge pull request #4796 from xXPBSXx/feat/socket-options-sol-socket
fix(libkernel): report SO_ERROR and the other SOL_SOCKET options like FreeBSD
2026-10-14 15:37:41 +13:00
Dean cdea950b7e
Merge pull request #4825 from StefanBuc/prepare/elf-import-audit-20261012
fix(tools): validate empty ELF dynamic symbol table bounds
2026-10-14 15:37:26 +13:00
Dean 1e277eef6e
Merge pull request #4930 from MarcZX100/fix/videoout-frame-dump-linear
fix(videoout): dump linear display buffers
2026-10-14 15:37:10 +13:00
Dean 91e5f60880
Merge pull request #4822 from MarcZX100/fix/fopen-native-open-errors-4814
fix(libc): return native fopen errors
2026-10-14 15:36:11 +13:00
Dean 6d032559c3
Merge pull request #4789 from PrintOrb/fix/audioout-shared-sdl-init
fix(audioout): serialize SDL audio initialization for Dark Forces
2026-10-14 15:35:56 +13:00
Dean 2ba3147ac8
Merge pull request #4844 from johnmaia/debug/skip-shader
feat(agc): skip the draws and dispatches of one shader with APS5_SKIP_SHADER
2026-10-14 15:32:04 +13:00
Dean 803cbf2f81
Merge pull request #4715 from Lorkydey/fix/agc-inactive-vertex-point-size
fix(agc): accept inactive vertex point size on non-point draws
2026-10-14 15:31:48 +13:00
Dean c5f839f651
Merge pull request #4702 from tv7/feat/gs-fast-launch
feat(agc): decode GS_FAST_LAUNCH geometry with one point per subgroup
2026-10-14 15:31:33 +13:00
Dean 0df6e295c5
Merge pull request #290 from MichonGoddijn231849/split/host-import-windows
feat(agc): host import windows, least-recent eviction under the budget
2026-10-14 15:27:19 +13:00
Dean 71c71f50b7
Merge pull request #5029 from fdfawef324/perf/agc-partially-resident-snapshot-hits
perf(agc): trust write stamps for snapshots of partially committed textures
2026-10-14 15:21:38 +13:00
pushkarreddyy fbf619ef0d
feat(libSceAgc): ignore address argument on non-sample-dump events in sceAgcDcbEventWrite 2026-10-14 07:37:02 +05:30
Dean 016db923af
Merge pull request #5184 from p3n1cillin/claude/sysctl-vm-overcommit
feat(libkernel): report vm.overcommit through sysctlbyname
2026-10-14 14:52:25 +13:00
AlxcBTW c29e06c693 fix(agc): a joined host import may replace imports the build in flight already holds
A join runs before any region confirms an import and a retired import lives
through the retire-hold, so refusing it for held overlaps kept the joined run
copied for the rest of the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:51:48 +13:00
Michon c871b5893d test(agc): host import windows, whole-range builds and budget refusals
agc_driver_graphics (BdaResources.cpp), each failing without its change:
- a view in the last window of a range whose first window was imported
  binds through an import of the whole range;
- an address-based build over the budget leaves the range's window in
  place (3 builds, same import);
- two uses across neighbouring cell edges share one import over 10
  rounds;
- a range mapped at the budget is refused at map time and retires
  nothing.
agc_driver_host_import_windows: windows follow their range, and
ClearHostImports drops them.
2026-10-14 14:51:48 +13:00
Michon e9249a0a47 feat(agc): host import windows, least-recent eviction under the budget
A registered range larger than 64 MiB is imported one 64 MiB window at a
time for buffer and fill accesses instead of whole, and the live imports
stay under a budget: APS5_HOST_IMPORT_MIB, else the larger of 6 GiB and
half the physical memory, at most the largest host heap less 2 GiB
(imports and type-3 mirrors share it; #167's rule). An import past the budget
retires the least recently used imports not used in the last 256
lookups.

- An access across window edges imports the cells it touches, grown to
  the union of the range's imports it overlaps, so uses across
  neighbouring edges share one import instead of replacing each other.
- An address-based build (AcquireRegistered) imports the range whole; a
  window over its first byte does not serve it.
- Every refusal (alignment, a failed run, a held import, the budget with
  what may be evicted) is decided before anything is retired.
- An import made when a range is mapped never evicts: the map observer
  holds no GPU lock.

The window size and the budget have setters for the tests.
2026-10-14 14:51:48 +13:00
Dean a98d42d08c
Merge pull request #4799 from ArjenS-LA/fix/trace-summary-selection
fix(tools): match explicit trace summaries to their capture
2026-10-14 14:51:27 +13:00
Dean 52d134c028
Merge pull request #4965 from pushkarreddyy/feat/agc-cmask-skip-higher-mip
feat(libSceAgcDriver): skip CMASK decode on single-sample views with viewMip > 0
2026-10-14 14:46:19 +13:00
Dean eacadec269
Merge pull request #4861 from Tamalero/fix/agc-metadata-pass-pass-through-depth
fix(agc): accept a CB metadata pass whose depth test passes every fragment without writing
2026-10-14 14:46:14 +13:00
Dean 959d39fb2b
Merge pull request #4801 from ArjenS-LA/fix/guest-posix-runpath
fix(relinker): validate Linux guest runpaths with target syntax
2026-10-14 14:45:57 +13:00
Dean 4586fdbc3b
Merge pull request #4469 from arcwiser/feat/libc-signal-list
feat(libSceLibcInternal): export sys_siglist and sys_nsig
2026-10-14 14:45:41 +13:00
p3nicillin dad29cac43 feat(libkernel): report vm.overcommit through sysctlbyname
The mimalloc in PS5MC (PPSA99420) reads vm.overcommit at start-up and
stopped on the unsupported name. It reports FreeBSD's default, 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:44:48 +13:00
Dean dff25dd604
Merge pull request #5098 from p3n1cillin/claude/sysctl-hw-realmem
feat(libkernel): report hw.realmem through sysctl
2026-10-14 14:44:32 +13:00
Dean 5a81f6085b
Merge pull request #4765 from nikowolf123/fix/conventions-template-subsections
fix(conventions): keep #### subsections inside the pull request template sections
2026-10-14 14:41:00 +13:00
Dean 1633843382
Merge pull request #4998 from ideabsassistenza/fix/debt-resolve-leading-entries
fix(debt): preserve leading entries during conflict resolution
2026-10-14 14:39:06 +13:00
Dean e5a272d7a6
Merge pull request #5359 from thuanquang/fix/output-path-directory
fix(relinker): reject a directory as the executable output path
2026-10-14 14:36:09 +13:00
Dean 3881dac903
Merge pull request #5148 from AaravMehta-07/codex/reject-relocatable-input
fix(relinker): reject relocatable ELF conversion inputs
2026-10-14 14:35:53 +13:00
Dean 54c2e14dc0
Merge pull request #5026 from AaravMehta-07/codex/reject-invalid-load-segments
fix(relinker): reject load file sizes beyond memory size
2026-10-14 14:35:37 +13:00
Dean e41cb23415
Merge pull request #5301 from wachi35676/fix/relinker-resource-path-spaces
fix(relinker): build the manifest resource in paths with spaces
2026-10-14 14:35:21 +13:00
Dean 52686e7959
Merge pull request #5300 from David-cmrg/fix/tests-ampr-cpp-error-pie
fix(tests): use position-independent unwind data in the C++ error fixture
2026-10-14 14:35:05 +13:00
Dean 4ddce7993d
Merge pull request #4845 from EagleBearerYS/test/guest-udp-readv-compare
test(libkernel): compare the unterminated readv buffer with memcmp
2026-10-14 14:34:41 +13:00
Dean 3e485ed53c
Merge pull request #4996 from MarcZX100/codex/mimg-sampler-vcc-4991
fix(shader): accept MIMG sampler tuples ending in VCC
2026-10-14 14:34:27 +13:00
Dean b9e0e4ed30
Merge pull request #5149 from xXPBSXx/fix/agc-texture-snorm-sint-2101010
fix(agc): sample 10_10_10_2 SNorm and SInt textures
2026-10-14 14:34:11 +13:00
Dean 97fce094c2
Merge pull request #5101 from Zheorgyan/fix/macos-import-lost-gpu-writes
fix(agc): make host imports over writable pages on macOS
2026-10-14 14:33:55 +13:00
Dean a87019d4ce
Merge pull request #4862 from Tamalero/fix/agc-blend-bypass-leaves-blending-off
fix(agc): leave blending off for a color target with CB_COLOR_INFO.BLEND_BYPASS
2026-10-14 14:33:39 +13:00
Dean 11b24ee816
Merge pull request #4863 from babyhuey/feat/libscevideoout-busy-open
fix(libSceVideoOut): return RESOURCE_BUSY when a bus is opened twice
2026-10-14 14:33:15 +13:00
Dean 8a437941bd
Merge pull request #4876 from EagleBearerYS/fix/savedata-failed-mount-keeps-result
fix(savedata): leave the mount result untouched when sceSaveDataMount3 fails
2026-10-14 14:32:59 +13:00
Dean 095a653c85
Merge pull request #5322 from lubaxe/fix/npauth-first-poll-running
fix(libSceNpAuth): report an async request as running on its first poll
2026-10-14 14:32:44 +13:00
Dean c5038c719f
Merge pull request #5170 from 0xRickx/fix/libscekeyboard-idle-count
fix(libSceKeyboard): report one key slot when no key is held
2026-10-14 14:32:30 +13:00
Dean 34355eeeac
Merge pull request #4942 from QRMOE/fix-libc-llroundl-upper-bound
fix(libc): accept the full llroundl integer range
2026-10-14 14:29:14 +13:00
Dean dd7174423a
Merge pull request #5009 from p3n1cillin/claude/libc-tzname
feat(libc): export tzname
2026-10-14 14:27:27 +13:00
Dean 0af3f150fa
Merge pull request #5153 from Kikoarl/feat/ces-sjis-cp932-profile-init
feat(ces): implement sceCesUcsProfileInitSJis1997Cp932
2026-10-14 14:27:11 +13:00
Dean 1535e2c688
Merge pull request #5414 from mariusyo07/feat/libc-mspace-aligned-alloc
feat(libc): implement sceLibcMspaceAlignedAlloc
2026-10-14 14:26:47 +13:00
Dean 1ebf8410a9
Merge pull request #5351 from MarcZX100/marc/fix-pathname-sysctl-eperm-5340
fix(libkernel): return EPERM before validating pathname sysctl MIB
2026-10-14 14:26:31 +13:00
Dean 2c444bb9fb
Merge pull request #5241 from MarcZX100/fix/sigwait-error-return-5224
fix(libkernel): return error numbers from sigwait
2026-10-14 14:26:15 +13:00
Dean 488ccece53
Merge pull request #4980 from MarcZX100/codex/poll-precise-wait-1471
fix(libkernel): use precise waits for empty poll sets
2026-10-14 14:26:00 +13:00
Dean 2e7ab67e8d
Merge pull request #4917 from MarcZX100/codex/carry-directory-read-4912
fix(libkernel): fail reads on Windows directory descriptors
2026-10-14 14:25:43 +13:00
Dean 7937c97237
Merge pull request #4923 from MarcZX100/codex/carry-ftruncate-not-file-4921
fix(libkernel): reject ftruncate on non-file Windows handles
2026-10-14 14:25:27 +13:00
Dean 8a51486bd2
Merge pull request #5393 from yixx16/fix/libkernel-vnode-windows-delete
fix(libkernel): keep the Windows vnode watch when the watched file is deleted
2026-10-14 14:25:11 +13:00
Dean d1c4618729
Merge pull request #4864 from milescoviello/carry/readv-pipe-windows-4858
fix(libkernel): fill every buffer of readv from a pipe on Windows
2026-10-14 14:24:56 +13:00
Dean c101c91bbb
Merge pull request #5272 from milescoviello/carry/siglongjmp-stack-windows-5270
fix(libkernel): switch the host stack bounds in siglongjmp on Windows
2026-10-14 14:24:40 +13:00
Dean 979a4b9bb7
Merge pull request #5464 from milescoviello/fix/kernel-stat-null-buffer
fix(libkernel): fail sceKernelStat with EFAULT for a null buffer
2026-10-14 14:24:24 +13:00
Dean c6926c9c00
Merge pull request #4958 from milescoviello/carry/flock-advisory-windows-4957
fix(libc): make flock advisory on Windows so other descriptors can read and write
2026-10-14 14:24:08 +13:00
p3nicillin fe54938490 feat(libkernel): report hw.realmem through sysctl
The dolphin_libretro core of RetroArch (PPSA99169) reads {CTL_HW,
HW_REALMEM} as the machine's memory size and stopped on the unsupported
MIB. It reports the same value as hw.physmem.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:23:55 +13:00
Dean fc1e388ed2
Merge pull request #5185 from p3n1cillin/claude/sysconf-clk-tck
feat(libkernel): report _SC_CLK_TCK through sysconf
2026-10-14 14:22:06 +13:00
arcwiser 8e0d6324af docs: group signal list debt with signal handling 2026-10-14 14:16:05 +13:00
screamm 9849a1db64 feat(libSceLibcInternal): export sys_siglist and sys_nsig
PS5CEMU-HAR (PPSA99360, ps5-payload-dev build, relinks with
--trap-sdk-syscall-stubs) imports the data objects sys_siglist
(yCdGspbNHZ8) and sys_nsig (ZD+Dp+-LsGg) from libSceLibcInternal.prx;
the import audit lists both as absent (registry entries 364 and 378,
after pthread_setaffinity_np at 276). No run has reached them yet; the
predicted stop line is

  FAIL: unresolved ELF import ZD+Dp+-LsGg (sys_nsig) from libSceLibcInternal.prx

or yCdGspbNHZ8 (sys_siglist), whichever the loader resolves first.

The table and count are FreeBSD 11.4 lib/libc/gen/siglist.c (8c639945):
32 descriptions, signal 0 to SIGUSR2 (NSIG 32), and sys_nsig is their
number, 32. ps5-payload-dev declares both as objects exported by
libSceLibcInternal and its strsignal reads them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-14 14:15:55 +13:00
pushkarreddyy acbc573212 feat(libSceAgcDriver): skip CMASK decode on single-sample views with viewMip > 0 2026-10-14 14:15:25 +13:00
Cesar Rodriguez 8c554cc42a fix(agc): accept a CB metadata pass whose depth test passes every fragment without writing
DecodeColorMetadataPass refuses an eliminate-fast-clear or DCC-decompress
pass when DB_DEPTH_CONTROL has any of its low four bits set and depth or
stencil planes are bound. Marvel's Guardians of the Galaxy (PPSA01748)
issues one with the Z test enabled, ZFUNC ALWAYS and no Z write
(DB_DEPTH_CONTROL 0x72) while a Z32 and an S8 target are bound. That test
passes every fragment and leaves depth unchanged, so the pass does no
depth work. Draws already treat this state as a pass-through
(depthPassThrough); the metadata pass now uses the same rule. Depth
bounds, depth writes, stencil tests and DB_RENDER_CONTROL clears or copies
are still refused, and the error names the four registers involved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:15:04 +13:00
ArjenS-LA 394c5a231e fix(relinker): validate Linux guest runpaths with target syntax 2026-10-14 14:14:38 +13:00
Dean ee9037d851
Merge pull request #4694 from EagleBearerYS/fix/agc-draw-snapshot-cap-at-build
perf(agc): read the draw snapshot cap when resources are built
2026-10-14 14:14:16 +13:00
Dean cd90ca50be
Merge pull request #4712 from Ondra97/codex/fix-debt-section-moves
fix(tools): preserve technical debt section moves
2026-10-14 14:13:58 +13:00
Dean b16a1a72f3
Merge pull request #4776 from babyhuey/feat/libkernel-sysctl-tsc-freq
feat(libkernel): report machdep.tsc_freq from sysctlbyname
2026-10-14 14:09:31 +13:00
Dean 19785b50e9
Merge pull request #4425 from Lorkydey/fix/import-audit-atomic-json
fix(import-audit): preserve JSON reports when writing fails
2026-10-14 14:06:16 +13:00
Dean d7bb2fee3d
Merge pull request #5580 from oneandonlydean/fix/videoout-dinput-1042
fix(videoout): disable SDL DirectInput joystick enumeration on Windows
2026-10-14 14:02:29 +13:00
Dean 604ce71864
Merge pull request #4947 from Kikoarl/perf/agc-draw-recipe-depth-expansion
perf(agc): expand draw recipes to support depth targets
2026-10-14 14:00:34 +13:00
Dean 1f1115dc90
Merge pull request #4795 from MarcZX100/codex/pipeline-cache-snapshot-lock-4781
fix(agc): serialize pipeline cache snapshots
2026-10-14 14:00:21 +13:00
Dean 0dea07ab27
Merge pull request #4517 from AlxcBTW/perf/host-import-join-exact
perf(agc-driver): join the imports of adjacent ranges of any size that a buffer is bound exactly over
2026-10-14 13:53:00 +13:00
thibaut b7d7e71bf6 docs(libc): move the Windows direct memory debt entry to libc.md
The entry links WindowsMappings.hpp, so the debt-file convention puts it in
docs/dev/debt/libc.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
thibaut f32a9407e4 test(libc): require resident direct memory in the resident run tests
CheckBreakingAResidentRunKeepsConcurrentAccesses and
CheckRemappedDirectMemoryIsChargedOnce passed on main, where a singly
mapped direct memory page is a shared view and no resident run exists.
Both now require their first mapping to be private committed memory, so
on main they fail there instead of passing without exercising a run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
thibaut 71da166a18 fix(libc): keep resident mappings to direct memory backings on Windows
Map made every singly mapped section page private resident memory. A JIT
or shm_open section is file backed and committed: its bytes live in the
file, and its alias descriptors map duplicated handles, which the physical
page slots do not match, so a resident copy diverged from the file, and
committing its view on a demote failed with access denied
(guest_jit_shared_memory). Only direct memory backings, mapped through the
new GuestArenaMapDirect, now become resident; other sections keep main's
shared views. Shared pages are committed only while their section page is
reserved, as on main.

The socket host write tests map their direct memory a second time, so the
write-protected shared path they check is still the one they exercise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
DotDebian d9852df2a2 fix(libc): track writes to singly mapped direct memory without faults on Windows
A direct memory page mapped at one guest address now lives in private
MEM_WRITE_WATCH memory at that address, and its writes are collected with
GetWriteWatch like flexible memory: no fault is raised. A page mapped at a
second address moves its whole resident run into the section, behind a
read-only fence while it is copied, and every address becomes a view of it,
tracked by write protection. Unmapped resident pages that are not blank are
kept in a private reservation until they are mapped again, not in the
section.

Ported onto main's 4 KiB subpage tracking of shared views: resident runs
keep a per-page collected bit and enter the fresh ranges, so Fresh and
Armed collections select them like shared views; a demoted run carries its
collected bits into the views and reports every page once. MapAlias throws
through refuse() when a resident run extends outside the aliased range, and
the caller keeps main's fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
MarcZX100 4307e3cb54 fix(agc): serialize pipeline cache snapshots 2026-10-14 13:34:43 +13:00
AlxcBTW d275a58814 fix(agc-driver): copy a region an exact join's import covers only in part
After an exact two-piece join, a bind across the join's end got the
joined import from importAllocation and the view failed as "rounded up to
its view range exceeds its GPU owner". UploadFinish now asks importJoined
for a region past the import's end and drops an import that still does
not cover the region, so the region is copied, as on main. The join test
binds across the end of an exact join after a third piece is registered.

Co-authored-by: TideOPL <57710757+TideOPL@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:34:31 +13:00
AlxcBTW ca95f74097 perf(agc-driver): join the imports of adjacent ranges of any size that a buffer is bound exactly over
A bound buffer is joined across adjacent registered ranges only when every
one of them is larger than the 8 MiB window. PPSA25344's loading binds 16 MiB
and 4 MiB buffers whose backing was registered in two to six adjacent
pieces with the same access, some of them smaller than the window, so each
use of such a buffer was copied on the CPU: up to 348 GB in the first 300 s
of loading.

A bound buffer that starts at the first crossed range's start and ends at the
last one's end now joins those ranges whatever their size. A heap grown in
pieces matches that only for a binding over exactly its current pieces, so
growth beside a joined import does not re-import it. joinedCovers, used when a
joined import retires, accepts any adjacent run of ranges.

importJoinTests binds exactly over two 64 KiB pieces of a partly filled
window and requires one import of both; a binding across them that starts
inside the first piece stays apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:34:31 +13:00
Dean ce5c839533
Merge pull request #4883 from nikowolf123/perf/shader-cache-resource-plan
perf(recompiler): keep the front-end resource plan in the shader disk cache
2026-10-14 13:33:01 +13:00
Dean 29d5f067b9
Merge pull request #5003 from tibzejoker/feat/depth-storage-array-views
feat(agc): storage image access to depth planes through 2D array views
2026-10-14 13:32:41 +13:00
Dean af991ac404
Merge pull request #4747 from TideOPL/perf/bc-block-copy
perf(agc): copy a pending block-compressed surface into its sampled texture on the GPU
2026-10-14 13:32:04 +13:00
Dean cb320fd884
Merge pull request #4603 from AlxcBTW/perf/agc-memory-value-fill
perf(agc): take the memory-value dword fill kernel as a buffer fill
2026-10-14 13:31:43 +13:00
Dean 520ee1a2e8
Merge pull request #4490 from karanvora2599/perf/shader-minmax-floor-denormal-free
perf(shader): treat f32 min, max, med3, floor and ceil results as denormal-free
2026-10-14 13:31:23 +13:00
Dean afc8541d18
Merge pull request #4487 from Pipodi/feat/agc-forced-srgb-views
feat(agc): sample non-sRGB textures through FORCE_DEGAMMA samplers as sRGB views
2026-10-14 13:31:02 +13:00
Dean 7cc6cd8633
Merge pull request #4465 from mrzacarias/fix/agc-buffer-pattern-fill
fix(agc): handle the fill kernel that reads its pattern from a buffer
2026-10-14 13:30:42 +13:00
JJenkx d1527840ea fix(libkernel): retire stack metadata before releasing mappings 2026-10-13 20:30:24 -04:00
fdfawef324 8d8fe39eed fix(agc): flush pending stores before a partial snapshot hit
A partially resident snapshot cannot be reused from committed write stamps while a recorder batch still owns an overlapping completion store. Make that case compare through the guest-memory flush hook before deciding whether the snapshot is unchanged.

Cover copied completion stores in both open and submitted batches, then verify that unchanged snapshots are reused and an unrelated pending write does not synchronize. The focused regression fails on the published PR head and passes with the guard. The existing fully committed snapshot path is unchanged.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-13 20:25:46 -04:00
fdfawef324 955b56a2b5 perf(agc): trust write stamps for snapshots of partially committed textures
A sampled texture over a partially resident surface (a texture array whose
heap the guest commits on demand) never got a write generation: CollectWrites
fails on a range with reserved pages, so every cache hit compared the whole
committed part with its snapshot. CollectCommittedWrites collects the
committed runs one by one and returns the runs with the generation; the cache
entry records them, and a hit skips the compare only when the committed runs
are the same and UnchangedCommittedSince holds over them. A commit, decommit,
view mapping or unmapping inside the surface changes the runs or stamps the
new pages, so it is compared as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:25:46 -04:00
Dean Galvin 56d1eda2f0 docs(videoout): record disabled DirectInput controller backend
Co-authored-by: Tenith01 <102300949+Tenith01@users.noreply.github.com>
2026-10-14 13:14:15 +13:00
Tenith01 e94f12bd17 fix(videoout): disable DirectInput joystick enumeration on Windows 2026-10-14 13:14:15 +13:00
Dean feddf7f4c6
Merge pull request #4849 from MarcZX100/codex/fix-address-cache-shutdown-4846
fix(agc): release cached address space on device teardown
2026-10-14 13:13:08 +13:00
Dean 014f3623a7
Merge pull request #4508 from jradelmo/feat/flexible-memory-budget
fix(kernel): honor the declared flexible memory budget
2026-10-14 13:13:03 +13:00
Kikoarl 3ebad9045e perf(agc): expand draw recipes to support depth targets 2026-10-14 02:00:40 +02:00
David-cmrg 75c25e16f0 fix(tests): use position-independent unwind data in the C++ error fixture 2026-10-14 01:49:52 +02:00
Dean d1670009fb
Merge pull request #5429 from Dripl1x/perf/windows-mutex-wake
perf(libkernel): wake guest mutex waiters on release on Windows
2026-10-14 12:31:24 +13:00
Evgeniy Kazarin 99eaf73102 perf(libkernel): wake guest mutex waiters on release on Windows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:18:33 +03:00
Adelmo Junior 12851ef037 docs: document flexible memory budget behavior 2026-10-13 20:13:14 -03:00
Adelmo Junior 72211b70fe fix(kernel): honor the declared flexible memory budget
Read the optional aligned budget from param.json and apply it consistently to configured, available and mapped flexible memory. Add parser and allocation regression coverage.
2026-10-13 20:13:14 -03:00
Dean 7a0c838ca4
Merge pull request #4875 from nikowolf123/perf/libc-write-watch-capacity
perf(libc): size each write-watch query to the region it covers
2026-10-14 12:12:10 +13:00
AlxcBTW 6ffc99bedb perf(agc): take the memory-value dword fill kernel as a buffer fill
The 9-word kernel #3816 matches stores one dword per thread, loaded with
s_buffer_load_dword through the descriptor in user[4..7]. Run as a
compute dispatch, its stores are pending writes of unknown value, so a
later read of DCC keys in that range waits for the GPU.

fillBuffer now takes it as a uniform buffer fill when all of these hold:
- the output descriptor's format is 32_UINT, 32_SINT or 32_FLOAT (20-22),
  so buffer_store_format_x stores the loaded dword unchanged;
- the value descriptor covers the loaded dword: num_records times the
  stride (num_records alone when the stride is 0) is at least 4 bytes,
  the range the recompiler gives a scalar buffer load;
- exactly 8 user SGPRs and group id X enabled, so the group id is s8;
- a direct, non-partial dispatch, 64x1x1 threads, one group in Y and Z,
  and a 16-byte aligned range of whole 16-byte units.

The value is read when the fill is recorded, after the labels queued
before it, as the pattern-fill kernel's source is. When the value is one
byte repeated and that byte is a DCC key code, the fill goes into the GPU
key-store memo whatever ClassifyFill reports: the memo answers a key
read only while this fill is still the newest pending write over the
keys, and a fill over a color target's keys is not a storage image's
keys fill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 00:44:41 +02:00
David 773e7f218c docs(debt): describe the byte the Windows flock locks 2026-10-13 22:29:33 +00:00
David b962be8536 test(libc): read and write through another descriptor while a flock is held 2026-10-13 22:29:20 +00:00
David 32fdaa65ae fix(libc): make flock advisory on Windows so other descriptors can read and write 2026-10-13 22:29:20 +00:00
Dean 30f961266a
Merge pull request #4973 from ducloc080202/fix/cq3-positioned-io
fix(libkernel): serialize positioned file transfers on Windows
2026-10-14 11:28:14 +13:00
Dean 83924acb18
Merge pull request #4467 from arcwiser/feat/libc-swscanf
feat(libc): implement swscanf
2026-10-14 11:27:57 +13:00
Dean Galvin 296ff64ae9 fix(libkernel): share positioned transfer locks on Windows only
The per-descriptor lock exists only in the Windows transfer path, so ShareDescriptor calls SharePositionedTransfer under _WIN32 like GuestFileLockShare. Linux failed to link libkernel with an undefined reference to it.
2026-10-14 11:18:55 +13:00
ducloc080202 0b46b3080a test(libkernel): cover concurrent pread against seek and read 2026-10-14 11:18:07 +13:00
ducloc080202 3cab3c05ec fix(libkernel): use per-descriptor locks for positioned transfers and seeks 2026-10-14 11:18:07 +13:00
Anshika Gupta 3915f6dc09 fix(libkernel): serialize positioned file transfers on Windows 2026-10-14 11:18:01 +13:00
screamm 8aa0d42824 feat(libc): implement swscanf
swscanf (HNnWdT43ues) runs the swscanf_s scanner without the buffer
size arguments after %s, %c and %[, as FreeBSD's swscanf.c passes its
arguments to vswscanf. Both entry points share one engine with a flag
for the sizes; swscanf_s behaves as before.

Title: PS5CEMU-HAR PPSA99360 imports swscanf from libSceLibcInternal.prx
(import audit with --trap-sdk-syscall-stubs, registry index 292, right
after pthread_setaffinity_np at 276). Predicted stop line once
pthread_setaffinity_np resolves, without this change:
FAIL: unresolved ELF import HNnWdT43ues (swscanf) from libSceLibcInternal.prx

NID from tools/nid_names.py, confirmed in shadPS4 aerolib.inl:51950
(e0a466753a1a). Prototype in ps5-payload-dev include/freebsd/wchar.h:133,
export in sce_stubs/libSceLibcInternal.c:8582 (f5d40f02770e).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-14 11:17:04 +13:00
Dean bf8dc610e6
Merge pull request #5425 from SandstromPL/feat/ces-module-library
feat(libSceCesCs): build libSceCesCs-module from the libSceCesCs source
2026-10-14 11:14:19 +13:00
Dean 703aa8f63d
Merge pull request #5411 from ps54all/feat/libscenet-resolver-ntoa6
feat(libSceNet): implement sceNetResolverStartNtoa6
2026-10-14 11:12:27 +13:00
Dean bfc10637d4
Merge pull request #5216 from oneandonlydean/up4/draw-key-second-sight
perf(agc): cache a draw key the second time it is seen
2026-10-14 11:06:03 +13:00
Dean 65beff9b19
Merge pull request #5478 from oneandonlydean/up4/sdwa-ubyte-1014
fix(recompiler): accept SDWA source selects on v_cvt_f32_ubyte1, ubyte2 and ubyte3
2026-10-14 11:05:47 +13:00
Dean c7601b7971
Merge pull request #4164 from hamb3r/feat/libc-unity-il2cpp-runtime
feat(libc): add missing Unity IL2CPP runtime imports and Dinkumware helpers
2026-10-14 10:45:32 +13:00
thibaut 696d1660c1 feat(agc): storage image access to depth planes through 2D array views
A 2D array storage view of a depth plane from slice 0 threw. It now gets
a storage image over all its slices: each slice with a depth surface at
the plane's address plus a whole depth slice per layer is copied from
that surface before every use and back after the work; the other slices
hold guest memory like any storage image. Cubes, stencil arrays, later
base slices and layer pitches other than the depth slice size still
throw.

GTA V (PPSA04264) stops at compute shader 0x242d4a200 on a 5-slice R32
Z_64KB_X array over its shadow depth surfaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-13 23:38:51 +02:00
Dean 665ad7da74
Merge pull request #4374 from MarcZX100/codex/carry-getpriority-3632
feat(libkernel): implement getpriority for the guest process
2026-10-14 10:36:42 +13:00
Hussein Kadhim 091438f99b fix(libkernel): fail sysctl with ENOTDIR when a leaf MIB has a trailing component
FreeBSD sysctl_find_oid returns ENOTDIR when the MIB continues below a leaf object. The supported hw.ncpu, hw.model, hw.physmem and kern.arandom MIBs threw an unsupported MIB error instead.

(cherry picked from commit 6968aea8af578c4d56dc614cbe449274bb6e76e7)
2026-10-13 21:33:25 +00:00
David 1ba0a81820 feat(libkernel): implement getpriority for the guest process
PS5MC (PPSA99420, Kodi 22) imports getpriority (miQ1wVwSexE) from
libkernel.prx, one reference, next to chflags in its import order.
Predicted stop once the imports ahead of it are covered (not a run):

  FAIL: unresolved ELF import miQ1wVwSexE from libkernel.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/kern/kern_resource.c sys_getpriority
(8c639945a44588f6cfdddfb057bb5aad88735da0) for the only guest process,
taken to run at nice 0 and to lead its own process group (as kill and
setsid already assume): PRIO_PROCESS and PRIO_PGRP with 0 or its pid,
and PRIO_USER with 0 or its uid 0, return 0; other ids give ESRCH and
an unknown which gives EINVAL. getpriority is a bare system call in
FreeBSD's libc (lib/libc/sys/Symbol.map), so errno is left unchanged
on success.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 63262245d274342b693fda146ae9feca3752b6e3)
2026-10-14 10:23:41 +13:00
Dean 8d98e8851f
Merge pull request #4474 from JJenkx/fix/multisample-target-retirement
fix(agc): retire fully unmapped multisample targets
2026-10-14 10:23:12 +13:00
Dean cf5f5b53b5
Merge pull request #4379 from MarcZX100/codex/carry-chflags-3632
feat(libkernel): carry chflags implementation
2026-10-14 10:22:02 +13:00
Dean d638e02860
Merge pull request #3991 from Sanjaysrinivas/perf/agc-lazy-storage-snapshot
perf(agc): allocate storage CPU snapshots on demand
2026-10-14 10:21:23 +13:00
Dean 7d757bbf0a
Merge pull request #4383 from pushkarreddyy/feat/libkernel-sigpending-sigsuspend
feat(libkernel): implement sigpending
2026-10-14 10:21:01 +13:00
Dean ea2b2d364f
Merge pull request #4514 from kallmek3nny/feat/libkernel-pthread-setaffinity
feat(libkernel): implement pthread_setaffinity_np
2026-10-14 10:20:33 +13:00
Dean Galvin 7b2104ee0d fix(recompiler): accept SDWA source selects on v_cvt_f32_ubyte1, ubyte2 and ubyte3
v_cvt_f32_ubyte0 accepts every SDWA source selector, but the other three byte
conversions had no VOP1 SDWA rule, so any SDWA source select on them was refused
("VOP1 SDWA source selector 4 of opcode 0x12 at pc 0xfcc is not supported").
The selected and optionally sign-extended source goes through the same operand
path as for ubyte0 before byte N is extracted: SDWA supplies source 0 (RDNA 2 ISA
guide 6.8 and 13.3.7) and the opcode reads S0.u[8N+7:8N] (12.8).

agc_driver_sdwa_cvt_f32_ubyte: WORD_0 and WORD_1 selects on ubyte1, and
sign-extended WORD_1 and BYTE_3 selects on ubyte2 and ubyte3.
2026-10-14 09:36:10 +13:00
MarcZX100 b6a10e91aa fix(libkernel): remove duplicate chflags error constant 2026-10-13 20:28:23 +00:00
Dean 0aa4cb1c2f
Merge pull request #3798 from YossiYad/carry/posixforwebkit-getservbyname
feat(libScePosixForWebKit): implement getservbyname
2026-10-14 09:24:05 +13:00
milescoviello eb78c6a45f fix(libkernel): fail sceKernelStat with EFAULT for a null buffer
Crimson Desert (PPSA25286) calls sceKernelStat with a null buffer at
start-up, and main throws "sceKernelStat: sb is null", which ends the
title in its first second.

FreeBSD 11.4 looks the path up first and only then copies the result
out, so a null buffer gets EFAULT for a path that exists and the lookup
error for one that does not (sys/kern/vfs_syscalls.c, sys_stat):

	error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
	    &sb, NULL);
	if (error == 0)
		error = copyout(&sb, uap->ub, sizeof (sb));

sceKernelStat now does the same: the lookup and its errors are as
before, and a null buffer returns SCE_KERNEL_ERROR_EFAULT where the
status would be copied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:20:07 +00:00
Dean a0f5916a29
Merge pull request #4417 from Jnbla6/fix/ngs2-rack-4001
feat(libSceNgs2.native): implement custom sampler rack id 0x4001 (#4334)
2026-10-14 08:55:20 +13:00
MarcZX100 852c808373 test(libSceNgs2): fix custom filter regression expectations 2026-10-14 08:47:31 +13:00
Zheorgyan 3960519b1e fix(agc): make host imports over writable pages on macOS
Co-authored-by: Marcio Rocha Zacarias <6743187+mrzacarias@users.noreply.github.com>
2026-10-13 21:43:21 +02:00
Dean Galvin 22f6b1735c docs: keep the technical debt index and end the NGS2 entry with a newline
The rebase onto main deleted docs/dev/TechnicalDebt.md, which is now the
index that points into docs/dev/debt/. Restore it from main and add the
missing final newline to docs/dev/debt/libSceNgs2.native.md.
2026-10-14 08:39:38 +13:00
jnbla6 40ebfae70b fix: throw on unsupported filter types and update debt docs 2026-10-14 08:39:32 +13:00
Jnbla6 ef52b16920 feat(libSceNgs2.native): add custom voice filter support and related tests for 0x13 issue case 2026-10-14 08:39:32 +13:00
Jnbla6 855823e85e feat(libSceNgs2.native): implement custom sampler rack id 0x4001 (#4334) 2026-10-14 08:39:32 +13:00
lorkydey d45fee9b69 fix(import-audit): preserve JSON reports when writing fails 2026-10-13 21:20:45 +02:00
mrfelek 48b69fad4d feat(libc): implement sceLibcMspaceAlignedAlloc 2026-10-13 21:20:32 +02:00
SandstromPL 299a736b54 feat(libSceCesCs): build libSceCesCs-module from the libSceCesCs source
Titles that link the character conversion library under its module name
need libSceCesCs-module.prx, which nothing built: Void Terrarium
(PPSA03061, #5055) and Call of Duty: Black Ops (PPSA34501, #5389) were
run with a copy of libSceCesCs.prx under that name. Both libraries are
now built from the same source by add_sce_ces_library, as libScePsml and
libSceFont-module are, and guest_ces_module runs the CesCs test against
the module-named library.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 00:44:56 +05:30
ps54all df32a44f79 feat(libSceNet): implement sceNetResolverStartNtoa6
Resolve a host name to its first IPv6 address through the host resolver
(getaddrinfo with AF_INET6) and write the 16-byte address. The lookup
shares the IPv4 path's resolver bookkeeping (abort preservation, error
state); a name without an IPv6 address fails with RESOLVER_ENODNS like a
failed lookup. Nonzero flags throw.

Metal Gear Solid 4 Master Collection (PPSA18194) imports it and failed to
load without it (unresolved zl35YNs9jnI from libSceNet.prx).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:13:34 +02:00
MarcZX100 2ad825f659 fix(shader): require the version 22 F16 request flag 2026-10-13 19:09:49 +00:00
MarcZX100 0e087e974e test(shader): cover version 21 F16 request layout 2026-10-13 19:09:49 +00:00
MarcZX100 dffdb5002e fix(shader): read both version 21 request layouts 2026-10-13 19:09:49 +00:00
Stefan Bucataru 89a8ec58b1 fix(tools): validate empty ELF dynamic symbol table bounds 2026-10-13 21:07:36 +02:00
Dean dacd78525e
Merge pull request #4949 from fdfawef324/fix/agc-unwritten-sample-locations
fix(agc): start the sample location registers at their clear-state value
2026-10-14 08:03:16 +13:00
MarcZX100 dfc9223248 docs(libkernel): retain chflags debt after rebase 2026-10-13 18:54:49 +00:00
MarcZX100 8b5cfb9850 test(libkernel): declare chflags guest entry point 2026-10-13 18:54:07 +00:00
David 4dd97f7dbe feat(libkernel): implement chflags through the guest path resolver
PS5MC (PPSA99420, Kodi 22) imports chflags (ixrw0h2tWuI) from
libkernel.prx, one reference. Predicted stop once the imports ahead of
it (pthread_getthreadid_np, sendfile, wcstok, pause, setrlimit and the
termios calls) are covered (not a run):

  FAIL: unresolved ELF import ixrw0h2tWuI from libkernel.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 (8c639945a44588f6cfdddfb057bb5aad88735da0)
sys/kern/vfs_syscalls.c kern_chflagsat and setfflags, and
sys/ufs/ufs/ufs_vnops.c ufs_setattr, for a root caller: the lookup
through the guest resolver gives EFAULT, ENOENT and ENOTDIR (also for a
file reached through a trailing slash or used as a directory), a bit
outside the 17 UFS flags of sys/sys/stat.h (VNOVAL included) gives
EOPNOTSUPP, and SF_SNAPSHOT gives EPERM, since the snapshot flag cannot
be toggled. No host keeps BSD file flags and stat reports st_flags 0,
so flags 0 succeed without touching the file and any other flag throws
with the flags named. UF_READONLY and the other Windows-attribute flags
are not mapped to FILE_ATTRIBUTE_READONLY and its siblings: UFS stores
them without enforcing them, and on Windows the read-only attribute is
already the owner write bit of chmod.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 16e5b7ccd04e6467a5a282b6cfc9271304f42244)
2026-10-13 18:54:05 +00:00
Jesus 50b06110bb fix(libkernel): keep the Windows vnode watch when the watched file is deleted
Windows 10 1903 deletes a file with open handles by moving it into
$Extend\$Deleted until the last handle closes, so the next snapshot of a
watched file that a title (or the test) deleted saw a new path, tried to
watch that directory's changes, got ERROR_ACCESS_DENIED and threw from
the watch thread, which aborts the process; the path change was also
reported as NOTE_RENAME next to NOTE_DELETE. A snapshot with a pending
delete or no links now reports NOTE_DELETE alone and drops the parent
directory watch instead of replacing it, as the file has no directory
to be renamed or removed from any more.
2026-10-13 13:41:05 -05:00
fdfawef324 15955c089e fix(agc): start the sample location registers at their clear-state value
A draw with PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES > 0 whose context never
wrote PA_SC_AA_SAMPLE_LOCS_PIXEL_* (context 0x2fe-0x30d) was rejected
with "missing register in context bank at DWORD 0x2fe", because the
registers were absent from the initial context (PPSA07411 stops on it
after two frames). The MSAA_ENABLE single-sample path read them the
same way.

The sixteen registers now start at 0, both initially and after
CLEAR_STATE. That is the value in libSceAgc's own register defaults
(sceAgcGetRegisterDefaults2, every public table that holds context
registers, the tables the initial context already follows for
PA_SU_VTX_CNTL and PA_SC_CONSERVATIVE_RASTERIZATION_CNTL), in amdgpu's
GFX10 clear-state table (clearstate_gfx10.h, gfx10_SECT_CONTEXT_def_8,
loaded by gfx_v10_0_cp_gfx_start before CLEAR_STATE) and the GC 10.3
register reset value (gc_10_3_0_default.h). RADV, radeonsi and PAL
always write the locations themselves and do not settle the unwritten
value.

0 puts every sample at the pixel center. That is not the standard
pattern for any sample count, so such a draw decodes as custom
locations at the center, as a single-sample scan into a multisampled
target already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:06:05 -04:00
thuanquang 286cf28ec7 fix(relinker): reject a directory as the executable output path
An existing directory, or a path ending in a separator, was only
rejected when the executable was written, after the converted modules
had already been written to app0/ beside or inside it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 00:49:48 +07:00
Dean 18c438b109
Merge pull request #4491 from xXPBSXx/fix/playgo-bound-no-chunk-table
fix(libScePlayGo): answer chunk ids from the package layout
2026-10-14 06:42:39 +13:00
Hussein Kadhim 2096410b29 fix(libkernel): report EPERM before EINVAL when writing kern.proc.pathname
FreeBSD sysctl_root rejects a write to a read-only node with EPERM before the node handler checks the MIB length, so a write with a short or long kern.proc.pathname MIB fails with EPERM. sysctlbyname for kern.proc.pathname now goes through sysctl with its 3-component MIB so it follows the same order.
2026-10-13 17:39:56 +00:00
Niko 5d3ea5f511 test(recompiler): set layerExported in the disk cache entry round trip
#5097 added ShaderInfo::layerExported to the entry encoder, and this
series moves that line into encodeShaderInfo, which plan entries use
too. The entry round trip left the flag false, so an encoder and a
decoder that both skipped it still passed. Set it like the other
ShaderInfo flags: with layerExported dropped from both, the round trip
now fails with "entry round trip: shader info differs".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:30:21 +02:00
boykopovar 8cf6a0bc3a
Merge pull request #5328 from boykopovar/chore/add-first-demo-collage
chore(readme): add games demo collage to readme
2026-10-13 20:18:47 +03:00
boykopovar bdded28693 chore(readme): add games demo collage to readme 2026-10-13 20:16:47 +03:00
Sasha Papo cb8b0caf7d fix(libSceNpAuth): report an async request as running on its first poll
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:07:19 -04:00
Dean 61b8742b6b
Merge pull request #4515 from AlxcBTW/perf/host-import-join
perf(agc-driver): join the imports of adjacent large ranges when a buffer is bound across them
2026-10-14 05:55:27 +13:00
Dean 9baec8793f
Merge pull request #3870 from yash27git/clean/Direct-Memory-Exception
fix(libkernel): harden DirectMemory validation and tests
2026-10-14 05:55:11 +13:00
Dean 40047f46bd
Merge pull request #4377 from MarcZX100/codex/carry-pthread-atfork-3628
feat(libkernel): implement pthread_atfork registration
2026-10-14 05:54:54 +13:00
Muhammad Wasif Ali Wasif 04421e7d4d fix(relinker): build the manifest resource in paths with spaces
windres passes include directories to the preprocessor unquoted, so
relinker.rc failed to compile when the checkout path contains a space.
The resource is now an object library without the relinker's include
directories.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:43:59 +05:00
screamm 74c3fb6576 feat(libkernel): implement pthread_setaffinity_np
PS5CEMU-HAR (PPSA99360, ps5-payload-dev build, relinks with
--trap-sdk-syscall-stubs) imports pthread_setaffinity_np (5KWrg7-ZqvE)
from libkernel.prx. babyhuey's run with #3787 merged onto main e7c70a2d
(PR #3787, 2026-10-12T10:54:44Z) stops at it:

  Windows: FAIL: unresolved ELF import 5KWrg7-ZqvE (pthread_setaffinity_np) from libkernel.prx
  Linux: undefined symbol: 5KWrg7-ZqvE (pthread_setaffinity_np)

It follows FreeBSD 11.4 libthr thr_affinity.c (8c639945) over
kern_cpuset_setaffinity: another thread is looked up first (EINVAL for
null, ESRCH when unknown or finished, as _thr_find_thread without dead
threads), a size other than the 32-byte cpuset_t returns ERANGE, the
mask is clipped to sceKernelGetAvailableCpumask and an empty result
returns EDEADLK, as cpuset_setaffinity does. The affinity is stored on
the guest thread through scePthreadSetaffinity, for the caller and for
any live guest thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:39:07 +00:00
Niko 664ad77037 test(recompiler): pin the field counts of the structures the plan codec writes
The plan and ShaderInfo encoders write these structures field by field,
and the sizeof asserts are their only reminder to update the encoders. A
field that fits in existing padding keeps the size: main's layerExported
landed in ShaderInfo with sizeof still 232, and the three bools #5089
adds to DescriptorSource::IndirectImage keep it at 28. A warm cache
would then hand back entries without the new field and nothing would
fail.

Count the fields of every aggregate the plan codec reaches (IrResourcePlan,
GuestRegister, MemoryInfo, DescriptorSource and IndirectImage,
ResourceBlock, SrtRead, UniformFill, UniformFillPlan, and ShaderInfo with
its resource and stage I/O records) by brace-initializing each with more
and more convertible-to-anything values until the initializer no longer
compiles, and assert the counts. Unlike the size asserts this does not
depend on the ABI, so it is checked on every platform. IrValue is a
class with private state and keeps only its size assert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:32:19 +02:00
Niko ce8944f853 test(recompiler): plan an invariant descriptor phi in the disk cache test
The round trip requires some fixture to plan a phi, and only one did:
the loop counter of "bindless sample in a loop latch", which reaches the
plan through the latch condition. The counter is not invariant, so the
CPU walk can never evaluate that condition. A plan that keeps only the
conditions the walk can evaluate, as #5181 aims to, would hold no phi
and fail the check with "no fixture plans a phi".

"descriptor invariant phi" loads the image descriptor from the same SRT
offset on both sides of a branch on an SRT dword. Its eight dwords are
phis of equivalent reads: the tracker keeps them, since it splits only
descriptor phis that are not invariant, and the walk evaluates them
through the invariant read. The plan stores them as descriptor dwords,
whichever conditions it keeps, so the phi encoding stays covered. The
fixture goes after the other compute fixtures, so they keep their seeds
and their damaged-entry checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Niko 70663fec42 test(recompiler): check that APS5_NO_PERF_DISK_PLANS=1 is cache-neutral
APS5_NO_PERF_DISK_PLANS=1 is listed as a neutral switch, so it stays out
of the variant key, and it exists to compare warm starts with and
without stored plans. Nothing tested either property: the cross-process
test ran with the switch unset only.

A fourth child process now sets the switch against the cache the first
process filled. It must run the front end for all 14 fixtures, neither
load nor store a plan, still hit all 14 stored variants, and produce the
same SPIR-V, bindings, push constants, snapshots, read traces and plans
as the first process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Niko a69f5e0371 test(recompiler): compare stored resource plans field by field
The plan tests compared a decoded plan with the original only through
the codec itself (re-encoding must give the same bytes) and through
materialization. Neither catches a field that EncodePlan and DecodePlan
both leave out: the bytes still agree, and the walk does not read every
field. Leaving userDataBase, the plan's sRGB formats, the value ids or
several MemoryInfo fields (secondaryOffset, dataDwords, dataFormat,
planningOnly, idxen) out of both sides passed every test. The hand-built
plan also never materializes (its uniform values cannot be evaluated),
so its 1000 runtimes all failed with the same error, and no plan held an
immediate wider than 32 bits.

samePlan compares every field of two plans without the codec: the value
graph by storage index (opcode, type, id, flags, register, immediate,
arguments, phi blocks), the block ids, the roots, and the plain data
through the structures' own equality. The round trip now requires it
for the 14 fixtures and the hand-built plan, which sets every MemoryInfo
field, all indirect table fields, a second buffer, the whole uniform
fill and a 64-bit immediate to values other than their defaults. The
second process also builds each fixture's plan with its own front end
and requires it to equal the plan it used, so a stored plan must match
what the front end builds in another process, not only its own
re-encoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Niko ed3f2776ed fix(recompiler): reject a stored plan whose image table names a missing source
DecodePlan checked every descriptor source index a plan holds except the
two inside an indirect image table: the heap source and the material
source. A damaged entry could therefore decode with a table that points
past the plan's descriptor sources, and only the materializer's own
bounds checks stood between it and an out-of-range read. The front end
interns both sources before the image source that names them, so a plan
it builds always passes the new check.

agc_shader_disk_cache now requires a plan whose table heap or material
source lies past the sources not to decode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Niko 1ed6c21067 perf(recompiler): load the resource plan from the disk cache before the front end
getSource built ResourceProgram (PrepareResourceProgram and ExtractPlan)
for the first request of every shader a process saw, before
findOrCompileVariant looked in the disk cache. With a warm cache every
launch still decoded, built the CFG, structurized, translated and ran
SSA, the fold passes, SrtWalker and ResourceTracker for every shader;
only SPIR-V emission was skipped.

getSource now builds the plan key and tries LoadPlan first. On a hit it
sets the plan and leaves the program null: findOrCompileVariant already
rebuilds the program when no stored variant fits the layout. The loaded
plan takes the request's code address as its shader hash, as a plan
built in this process would. On a miss it builds the plan as before and
stores it. A plan the front end refuses is not stored. The disk is not
used when the cache is off, under the debug probe, with APS5_DUMP_IR
(which prints the front-end passes), or with APS5_NO_PERF_DISK_PLANS=1,
a cache-neutral switch for comparisons.

FrontEndBuilds() counts PrepareResourceProgram calls. The new
cross-process test prepares, captures and materializes 14 shader
fixtures in one process and repeats it in a second process sharing the
cache directory: the second process must run the front end 0 times, hit
14 plans and 14 variants, and produce byte-identical SPIR-V, bindings,
push constants, snapshots, read traces and plans. A damaged plan entry
is rejected and rebuilt alone with the same output and stored again; a
changed code word and another switch value miss.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Niko 0c144502e5 feat(recompiler): store front-end resource plans in the shader disk cache
The disk cache keeps compiled variants (SPIR-V, shader info, binding
layout) but not the IrResourcePlan the front end extracts for the
resource walk, so a process can only get a plan by running the whole
front end. Since #471 the plan owns its values (ownPlanValues clones the
graph behind every root into valueStorage and blockStorage), so it can
be written out and rebuilt.

- EncodePlan writes the value graph in storage order, each value as
  LEB128 integers: opcode, type, id, flags, register, operand count,
  the immediate if it has one, each argument as the zigzag distance to
  the value's own index (0 for null) and, for phis, the index of each
  predecessor block. The roots (descriptor source dwords, SRT reads,
  control-flow conditions, uniform-fill values) are value indices; the
  plain data (memory info, indirect image tables, control-flow edges,
  materialization sources, guarded, clean and pure flat slots, the
  flags, the ShaderInfo through the variant's encoder) follows. A plan
  whose roots or arguments point outside its storage is not encoded.
  Control-flow conditions can pull most of a program into the plan:
  a synthetic 2,038-dword compute shader with a branch every 20 dwords
  has 42,775 plan values, which take 518 KB this way and 2.5 MB with
  fixed-width fields; its compiled variant entry is 935 KB.
- DecodePlan rebuilds the graph the way ownPlanValues does and rejects
  an unknown opcode, an overlong integer, an index past the values or
  blocks, a descriptor source, image, buffer or sampler past the
  sources, a branch without two successors, an edge past the blocks,
  and a uniform fill of more than four words.
- BuildPlanKey is the in-memory source key (RecompileCacheKey::Build and
  the host subgroup size), every code word and the switch key, after a
  plan entry tag. It leaves out the binding layout, so all layouts of a
  shader share one plan.
- EncodePlanEntry/DecodePlanEntry use the variant's header and hashes;
  LoadPlan and StorePlan use the same directory and background writer
  and count plan hits, misses, writes and load failures on their own.
- Size asserts cover the plan and the structures it is written from.
- FormatVersion 30.

agc_shader_disk_cache now round-trips the plans of 14 in-tree shader
fixtures (SRT reads, guarded and chained pointers, control-flow
conditions, an indirect image table, a loop phi, a fragment shader) and
a hand-built plan with a uniform fill. For each it materializes the
original and the decoded plan over 1000 random user-data and memory
runtimes and requires the same snapshot, poison, null-root count and
read trace, or the same error. Truncated, bit-flipped and
other-format entries are rejected, malformed plans do not decode, and
the key follows the code, the target and the host subgroup size but not
the layout, addresses or user data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:31:17 +02:00
Hussein Kadhim 37ea3b651a fix(libc): finish the exit handlers when one of them calls exit
A guest handler that called exit threw out of the libc exit path because the exiting thread waited on itself. Like FreeBSD, the nested call now runs the handlers that are still registered and ends the process with the status it passed.
2026-10-13 16:28:00 +00:00
Niko 5c802bbf10 refactor(recompiler): split the ShaderInfo encoder and the entry envelope
encodeInfo and decodeInfo wrote the ShaderInfo fields inline between the
compiled-shader header and the binding layout, and EncodeEntry and
DecodeEntry built and checked the file header (magic, format, source
version, key and payload hashes) inline. Move both into helpers,
encodeShaderInfo/decodeShaderInfo and wrapEntry/unwrapEntry, so that a
second kind of entry can reuse them.

The bytes of a compiled variant entry do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:23:35 +02:00
Hussein Kadhim ac82f3c6a9 fix(libkernel): switch the host stack bounds in siglongjmp on Windows
longjmp moves the Windows stack bounds onto the stack of the target jump buffer so that exceptions and stack probes keep working after a jump between guest stacks. siglongjmp restored the same registers without that step, so a jump from a context stack back to the thread stack left the thread bounds describing the stack it had left.
2026-10-13 16:09:27 +00:00
hamb3r 8652dbe35b feat(libc): add missing Unity IL2CPP runtime imports and Dinkumware helpers
Add missing libc.prx symbols required by Unity IL2CPP runtime:
- Implement _Dtest double classification in Math.cpp
- Implement _Inf double constant in Math.cpp
- Implement sceLibcBacktraceGetBufferSize and sceLibcBacktraceSelf in Backtrace.cpp
- Implement _Cnd_signal in Threads.cpp
- Implement _ZNSt8ios_base7_AddstdEPS_ in RuntimeSupport.cpp
- Implement __pointer_type_info and __function_type_info vtables in TypeInfo.cpp
- Remove duplicate stubs from libSceAmpr/Export.cpp
- Add unit tests in GuestMath.cpp and GuestLibcThreads.cpp
- Document unverified behaviors in docs/dev/debt/libc.md
2026-10-13 19:01:30 +03:00
Adrià 0214069e33
Merge pull request #5263 from adriadam10/ci/mesa-cache-per-cpu
ci(build): key the Mesa shader cache by the runner's CPU flags
2026-10-13 17:58:02 +02:00
Adrià Franch 32accfa938 ci(build): key the Mesa shader cache by the runner's CPU flags
The cache from #5107 was keyed by Mesa version only, so a runner restored
llvmpipe code compiled on another runner's CPU and about 85 agc tests died
with SIGILL (Illegal instruction) on main.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 17:57:49 +02:00
NaitikJoshiPro 6f856a7cda feat(relinker): executable TLS relocations (TPOFF64, DTPOFF64, DTPMOD64)
A PS5 eboot can keep initial-exec TLS as R_X86_64_TPOFF64 GOT relocations
(SuperTuxKart, STKT00001, has 13, all without a symbol), which the
relocation allowlist rejected. Relocations against the executable's own
TLS block (no symbol, or a defined STT_TLS symbol folded into the addend)
now go to the Linux ELF as symbolless dynamic relocations that the
dynamic loader resolves against where it placed the block; one against an
import stays named and is typed STT_TLS. The Windows and macOS images
resolve TPOFF64 and DTPOFF64 statically against the block
AlignUp(p_memsz, p_align) below the thread pointer, the offset
WindowsTlsBuilder and MacOsImage use, and reject DTPMOD64 and imported
TLS. TPOFF32 stays unsupported.

New test executable_tls_relocations covers the Linux, Windows and macOS
outputs and the rejected cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:24:37 +05:30
Adrià 9d0a41d5a1
Merge pull request #4611 from EagleBearerYS/fix/libscenet-epoll-out
fix(libSceNet): sceNetEpollWait takes 2 as the OUT event
2026-10-13 17:51:30 +02:00
Adrià 34cee1ef15
Merge pull request #4608 from MiniRML/fix/relinker-icon-png-chunks
fix(relinker): validate icon PNG critical chunks and order
2026-10-13 17:50:39 +02:00
Adrià 3e8d0793b7
Merge pull request #4588 from Nixitov/feat/libkernel-host-hardware
feat(libkernel): report the host SoC and CPU temperature
2026-10-13 17:49:54 +02:00
MarcZX100 85c090d49d test(libkernel): verify sigwait preserves errno 2026-10-13 15:49:45 +00:00
Hussein Kadhim 13b4de565b fix(libkernel): return the error number from sigwait
FreeBSD's sigwait hands the error number back as its return value and leaves errno alone; the guest export returned -1 and set errno.

(cherry picked from commit b627f6c9443dd94a6392959f33e52d837ee4cae4)
2026-10-13 15:49:28 +00:00
Adrià 27477e5f47
Merge pull request #4583 from MiniRML/fix/relinker-section-name-address
fix(relinker): zero the unmapped section-name table address
2026-10-13 17:49:15 +02:00
Adrià 8b20708599
Merge pull request #4579 from MiniRML/fix/release-configured-windows-runtime
fix(release): find the configured Windows runtime
2026-10-13 17:48:48 +02:00
Adrià 9dd3c2d1a6
Merge pull request #4547 from codingreapermaps/feat/relinker-trace-imports
feat(relinker): add --trace-imports for Windows executables
2026-10-13 17:48:21 +02:00
Adrià 67e86d93d5
Merge pull request #4250 from shahulmubeen-a/perf/shader-byte-buffer-stores
perf(shader): store 8- and 16-bit buffer components as bytes
2026-10-13 17:47:54 +02:00
Adrià c7beafd21a
Merge pull request #5256 from adriadam10/fix/libc-acosf-nan-bits
fix(libc): choose the acosf NaN bits instead of the host libm
2026-10-13 17:46:36 +02:00
Adrià Franch 0265f33636 fix(libc): choose the acosf NaN bits instead of the host libm
FreeBSD msun e_acosf.c returns (x-x)/(x-x) for |x| > 1 and NaN inputs: the
x86 default NaN 0xffc00000, or the quieted input NaN. std::acos left it to the
host libm, and guest_math failed on the runner's glibc 2.39.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 17:46:18 +02:00
Adrià 091c136ba6
Merge pull request #5223 from Nixitov/feat/libc-float-math
feat(libc): implement the missing float rounding and classification exports
2026-10-13 17:43:06 +02:00
Adrià 6679168360
Merge pull request #5210 from ErenYeager1836/carry/libkernel-coredump-user-file
feat(libkernel): answer the coredump user-file attach calls
2026-10-13 17:42:50 +02:00
Adrià 5030fbb5cb
Merge pull request #5201 from ErenYeager1836/carry/libkernel_sys-chroot
feat(libkernel_sys): implement chroot with FreeBSD lookup semantics
2026-10-13 17:42:22 +02:00
Niko 0f7cd5b7ac fix(conventions): skip library test fixtures in the export checks
The duplicate-export and silent-stub rules treated every APS5_VABI
definition under core/libs/prx/ as a library export, including mocks
and callbacks in a library's tests/ directory. Those files are built
only into separate test executables, never into the library, so they
are not exports. PR #3533 failed CI because a sceKernelGetProcessTime
mock in libSceAudioOut/tests was reported as a duplicate of libkernel's
export. An sce* fixture with a stub-shaped body was also reported as a
silent stub, and a real export that shares a name with a fixture in
another library's tests/ was reported as a duplicate.

Skip files under a tests directory on both sides of the check, with the
same test code() already uses for title-specific and progress.py uses
for its function counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:39:20 +02:00
Adrià fdefd76609
Merge pull request #4705 from karanvora2599/perf/shader-unary-input-flush-once
perf(shader): drop the input flush that rcp, rsq, sqrt, exp and log results never use
2026-10-13 17:38:07 +02:00
Adrià e6fae88a42
Merge pull request #4684 from XairRrR/fix/agc-acquire-without-waiting
fix(agc): drop a presentation instead of waiting for a swapchain image
2026-10-13 17:36:29 +02:00
Adrià 068ab2aba6
Merge pull request #4638 from MarcZX100/codex/carry-win-getdents-throw-3327
fix(libkernel): throw for oversized directory entries
2026-10-13 17:32:31 +02:00
Adrià 6629c09392
Merge pull request #4619 from MiniRML/fix/nid-version-requirement-chains
fix(nid): bound version requirement chains to their section
2026-10-13 17:31:25 +02:00
Adrià 3f2782cc7c
Merge pull request #4618 from Borooooo/fix/relinker-long-paths
fix(relinker): accept paths longer than 260 characters on Windows
2026-10-13 17:31:05 +02:00
Adrià 765661581b
Merge pull request #4613 from EagleBearerYS/fix/libscenet-copied-address-length
fix(libSceNet): report copied socket address lengths
2026-10-13 17:30:34 +02:00
Adrià c35bc4b92c
Merge pull request #4612 from EagleBearerYS/fix/libscenet-epoll-ident
fix(libSceNet): report the registered socket as the epoll event ident
2026-10-13 17:30:05 +02:00
Adrià 2f6ae9fc88
Merge pull request #4610 from EagleBearerYS/fix/libscenet-sce-socket-timeouts
fix(libSceNet): take 0x1105 and 0x1106 as the send and receive timeouts
2026-10-13 17:28:11 +02:00
Adrià 842766d39c
Merge pull request #4606 from Nixitov/feat/import-audit-stop
feat(tools): report each converted title's current stop in import_audit
2026-10-13 17:26:59 +02:00
Adrià 9c4686321b
Merge pull request #4604 from MiniRML/fix/nid-gnu-hash-geometry
fix(nid): validate GNU hash geometry before rewriting
2026-10-13 17:26:25 +02:00
Adrià 284cb63dc9
Merge pull request #4601 from MiniRML/fix/nid-pe-export-references
fix(nid): resolve PE reference exports through their ordinals
2026-10-13 17:26:06 +02:00
Adrià 39890031e3
Merge pull request #4591 from MiniRML/fix/oracle-input-rows
fix(oracle): validate input words before tool lookup
2026-10-13 17:25:30 +02:00
Adrià a56c905df6
Merge pull request #4589 from MiniRML/fix/tools-cut-helper-accounting
fix(tools): exclude cut helpers from NID accounting
2026-10-13 17:24:55 +02:00
Adrià 9c05bf25f5
Merge pull request #4585 from jagrat04/feat/libkernel-cpuset-affinity-errors-pr
feat(libkernel): return ESRCH and EINVAL for unsupported cpuset affinity targets
2026-10-13 17:23:01 +02:00
Adrià 5a76fd716f
Merge pull request #4575 from MiniRML/fix/progress-raw-string-literals
fix(progress): ignore C++ raw-string contents
2026-10-13 17:19:23 +02:00
Adrià 382c451acf
Merge pull request #4564 from MiniRML/fix/nid-windows-unicode-paths
fix(nid): preserve Unicode paths on Windows
2026-10-13 17:19:00 +02:00
Adrià c422b57fb3
Merge pull request #4672 from milescoviello/carry/lseek-pipe-windows-4670
fix(libkernel): fail lseek on a pipe with ESPIPE on Windows
2026-10-13 17:13:35 +02:00
Adrià 7e4edf509a
Merge pull request #4616 from EagleBearerYS/fix/libc-strtod-quiet-nan-windows
fix(libc): return the default quiet NaN from the strtod family
2026-10-13 17:11:55 +02:00
billybobpicklio d7818c9e55 fix(agc): accept integer tessellation partitioning
A draw with VGT_TF_PARAM.PARTITIONING 0 (PART_INTEGER) was refused by the
state decoder and its hull and domain programs by the recompiler. It is now
drawn with Vulkan's equal spacing, the mode radeonsi programs as
PART_INTEGER, with tessellation factors bounded at 64 instead of
fractional-odd's 63. Power-of-two and fractional-even partitioning still
throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:11:46 -04:00
Adrià cba01c87d1
Merge pull request #4614 from EagleBearerYS/fix/libscenet-getsockname-unbound-windows
fix(libSceNet): name an unbound socket with the zero address on Windows
2026-10-13 17:11:20 +02:00
Nixitov 00f0589101 feat(libc): implement the float rounding and classification exports
PPSA99611 imports ceilf, floorf, truncf, isnan and isinf from libc.prx and stops at start-up on main. Implement them next to the existing double forms: the rounding results delegate to the standard library like the other float exports, and isnan/isinf reuse the __isnan/__isinf helpers isnanf already uses.
2026-10-13 17:09:47 +02:00
Adrià 242bae7445
Merge pull request #4597 from MiniRML/fix/release-destination-preflight
fix(release): preflight asset destination types
2026-10-13 17:07:51 +02:00
Adrià 9510e71d6a
Merge pull request #5221 from adriadam10/ci/dispatch-without-linux
ci(build): let a dispatched build skip the Linux job
2026-10-13 17:05:09 +02:00
Adrià eb5bee4bfe
Merge pull request #4557 from saxopa/fix/relinker-linux-program-header-slots
fix(relinker): move the Linux program header table when it has no free slot
2026-10-13 17:04:41 +02:00
Adrià 8bf10e51f4
Merge pull request #4554 from queeeef/fix/agc-sampled-dcc-key-writers
fix(agc): wait for recorded writes over a sampled texture's DCC keys before reading them
2026-10-13 17:04:12 +02:00
Adrià Franch 71f98dd746 ci(build): let a dispatched build skip the Linux job
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 17:03:50 +02:00
Adrià d67a9e5a45
Merge pull request #4553 from Nixitov/feat/fchmodat
feat(libkernel_sys): implement fchmodat
2026-10-13 17:03:44 +02:00
Adrià 1a217cd4a3
Merge pull request #5204 from ErenYeager1836/carry/appcontent-addcont-enqueue-download
feat(libSceAppContent): implement sceAppContentAddcontEnqueueDownload
2026-10-13 17:02:04 +02:00
Adrià a74f2efe84
Merge pull request #5097 from TideOPL/fix/ancillary-layer-export
fix(shader): read the ancillary render target index from Layer when the draw exports it
2026-10-13 17:01:11 +02:00
Adrià Franch 1a2a4265c1 docs(debt): record the GS_FAST_LAUNCH decode assumptions 2026-10-13 17:00:51 +02:00
Lexroid 7370aaf6d0 feat(agc): decode GS_FAST_LAUNCH geometry with one point per subgroup
VGT_SHADER_STAGES_EN.GS_FAST_LAUNCH = 1 (mesh-style NGG, as RADV programs
it on gfx10.3) was refused. With a point list and GE_CNTL groups of one
point, it launches one subgroup per input point and the first thread
reads that point's index in the ES vertex id VGPR, which the mesh
prologue already provides. The subgroup's primitive limit comes from
GE_NGG_SUBGRP_CNTL.PRIM_AMP_FACTOR, and the GS and ES VGPR counts are
not required to be full.

Fast launch 2, other group sizes or inputs, and indexed fast-launch
draws still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:00:45 +02:00
adriadam10 bc568a1f6f fix(input): MouseModeEnabled reads the keyboard/mouse state
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 17:00:28 +02:00
AlxcBTW 38bc0fd348 feat(input): turn mouse speed into a smooth right-stick tilt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:00:20 +02:00
Adrià 3b94f923a5
Merge pull request #4633 from QRMOE/fix-libc-wcsxfrm-truncation
fix(libc): terminate truncated wcsxfrm results
2026-10-13 17:00:13 +02:00
Adrià fffe7351ad
Merge pull request #4625 from QRMOE/fix-libc-strtok-exhausted-state
fix(libc): clear exhausted strtok continuation state
2026-10-13 16:59:43 +02:00
Adrià 72a8e67122
Merge pull request #4621 from MiniRML/fix/nid-elf-shared-string-roles
fix(nid): preserve each ELF string consumer independently
2026-10-13 16:59:13 +02:00
codingreapermaps 430e5c833e feat(relinker): add --trace-imports for Windows executables
With --trace-imports the entry stub resolves TraceImport_nid_no_patch
in libc.prx and passes each function import through it before writing
the slot: every PLT slot, and a GOT slot only when the original symbol
is a function, so data imports such as __stdoutp keep their address.
Without the option the output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:55:31 +02:00
Dean Galvin 0adbdcf45c perf(agc): cache a draw key the second time it is seen
A draw whose key has no entry captured its stages, built a variant per
stage (a copy of every captured region) and inserted a draw entry. A key
that never comes back paid for the variants and the entry for nothing,
and its entry pushed a live one out of the cache. Draws whose user data
changes every frame are such keys.

The driver now remembers the keys it has seen once, in a table of
four-way buckets holding four times the cache's size in keys. A key gets
its entry at its second sight; a key that already has an entry still
takes new variants at once. A full bucket replaces its oldest key, so
keys that share a bucket do not push each other out until more than four
of them come between two sights of one.

Test: agc_driver_draw_cache_reuse draws three times. The first two draws
find no entry, one entry is inserted, and the third draw hits it. A
sighting table of one bucket keeps two keys drawn in turn and replaces
its oldest key when full.
2026-10-14 03:53:28 +13:00
Adrià 60fb618708
Merge pull request #4551 from eljackjoestar-cmd/codex/preserve-color-slice-xor
fix(agc): preserve array slice XOR in color target views
2026-10-13 16:52:35 +02:00
Adrià c496fd530f
Merge pull request #4546 from codingreapermaps/feat/libc-call-trace-runtime
feat(libc): record traced import calls on Windows
2026-10-13 16:51:55 +02:00
Nixitov a3a3f3a9ce feat(tools): report each converted title's current stop in import_audit
The stop is the first unresolved import in the registry order, the line the loader fails on. Print it per registry and add it to the --json result.
2026-10-13 16:50:51 +02:00
Adrià b8683834f3
Merge pull request #4596 from MiniRML/fix/oracle-target-override
fix(oracle): honor the current target override
2026-10-13 16:48:06 +02:00
Adrià f2c314e902
Merge pull request #4577 from Moaziz667/fix/prime-remaining-host-mutexes
fix(agc,shader): prime the remaining host shared mutexes
2026-10-13 16:45:17 +02:00
Rick 8ea8ea386a fix(libSceKeyboard): report one key slot when no key is held
A keyboard record on the console never counts fewer than one key: with
nothing held, and with no keyboard connected, the count is 1 and that
slot holds code 0. SharpProspero's keyboard reader, PS5_Quake3e's notes
on records read from a console and the PS5 input research notes all say
so. AnyPS5 reported a count of 0. The count is now at least 1; the key
slots themselves are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 16:44:17 +02:00
Adrià 2f5c3a4bf5
Merge pull request #4559 from MarcZX100/codex/import-audit-sectionless-modules
fix(tools): audit sectionless guest modules
2026-10-13 16:43:53 +02:00
Adrià b4d76ba609
Merge pull request #4556 from Amoenus/codex/fix-inactive-covered-centroid
fix(agc): admit inactive covered-centroid mode
2026-10-13 16:43:05 +02:00
screamm 204355cc64
feat(libkernel): answer the coredump user-file attach calls
sceCoredumpAttachUserFile (5nc2gdLNsok) and
sceCoredumpAttachMemoryRegionAsUserFile (MEJ7tc7ThwM) get the
signatures of Orbital's db_types.json (cc408367) and SharpProspero's
KernelSystem.cs (5dfdb4b0): (uint32_t userValue, const char* path) and
(uint32_t userValue, const void* mem, size_t size, const char* name).

The handler is never invoked here, so both return
SCE_COREDUMP_ERROR_NOT_IN_COREDUMP_HANDLER (0x81180003, shadPS4
coredump_error.h e0a46675) and attach nothing; a null path or name and
a null, empty or wrapping region throw because the order of the
console's checks is unknown.

Carried from @screamm with author attribution preserved.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 20:11:39 +05:30
Adrià ffa2a6ecd3
Merge pull request #4550 from MiniRML/fix/nid-buffer-validation
fix(nid): validate buffer ranges and string terminators
2026-10-13 16:41:04 +02:00
SandstromPL 78f620cf9e fix(relinker): keep code analysis inside the code extent of PS4 executables
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:10:51 +05:30
Adrià 69b4ca5d9b
Merge pull request #4215 from Mouad-Scriptz-0/fix/agc-flip-eop-event
fix(libSceAgcDriver): raise the graphics end-of-pipe event from flip packets
2026-10-13 16:39:04 +02:00
MiniRML bfffd3359c fix(relinker): validate icon PNG critical chunks and order 2026-10-13 16:38:28 +02:00
Nesyth 417ea99df5 fix(libkernel): zero-fill APR reads that reach the end of the file 2026-10-13 16:38:17 +02:00
Zenodeon b6c224af45 fix(relinker): keep diagnostics compatible with pending refactors 2026-10-13 18:37:50 +04:00
Zenodeon 36c11dc926 fix(relinker): identify failed inputs and invalid dynamic values 2026-10-13 18:37:50 +04:00
JJenkx f7fd7569fa fix(agc): retire fully unmapped multisample targets 2026-10-13 10:37:07 -04:00
Shahul Mubeen A 066a8fbe30 perf(shader): store 8- and 16-bit buffer components as bytes in compute
A formatted store of an 8- or 16-bit component into a bound buffer
patched the dword around it with a compare-exchange loop (writeBuffer
in SpirvRuntimeBuffer.cpp). Ghost of Yotei's light-culling compute
pass (program 0x800038be00, 240x135 groups per frame) stores millions
of such components per dispatch and took 426 ms of GPU time per
dispatch on an RTX 4070 Ti SUPER.

Compute stores now go through a byte view of the bound buffers
(buffers_u8, an aliased declaration of the buffers binding, defined
on the first narrow store): one OpStore per byte under
StorageBuffer8BitAccess, which the shader device profile already
requires. Without the capability, and in every other stage, the
compare-exchange path remains: the draw-time validator accepts only
u32 and u64 aliased views. Loads, dword stores and stores through
GPU-selected descriptors (BDA) are unchanged.

Ghost of Yotei (PPSA26344 02.002.000), Windows 11, RTX 4070 Ti SUPER,
logo phase: that dispatch 426 -> 10.7 ms of GPU time, 1.9 -> 11 fps.

agc_formatted_buffer_byte_stores compiles a formatted 8_8_8_8 store
as compute with and without StorageBuffer8BitAccess and as a vertex
shader with it, and checks the byte view, the byte stores, the
compare-exchange loops and the fallbacks. agc_driver_formatted_store_unaligned
executes 8- and 16-bit formatted stores at misaligned offsets,
including stores that cross a dword, and checks every byte of the
output including the untouched neighbours.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 16:36:56 +02:00
Adrià e0d388fa28
Merge pull request #4555 from Xabilimon1/fix/macos-build-libkernel-getrlimit
fix(libkernel): build the fcntl status flags and the getrlimit test on macOS
2026-10-13 16:36:38 +02:00
Adrià Franch c6b1f84a7e docs(debt): record sceAppContentAddcontEnqueueDownload behaviour as unverified 2026-10-13 16:33:51 +02:00
David fdfe2204aa feat(libSceAppContent): implement sceAppContentAddcontEnqueueDownload
The signature (uint32_t service label, const NpUnifiedEntitlementLabel*)
follows SharpProspero Interop/AppContent/AppContent.cs (5dfdb4b0). dlc_emu
dlc_content.cpp (fcf69b16) answers NOT_FOUND for a label that is not a
known add-on and PARAMETER for a null label. No add-on content is ever
installed here, as sceAppContentAddcontMount and sceAppContentGetAddcontInfo
already model, so every non-null label answers NOT_FOUND and nothing is
queued. dlc_emu's nonzero-padding check is left out, as sibling functions
do not check it and no console source confirms it.

Carried from @screamm with author attribution preserved.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:33:45 +02:00
Adrià b478fbbb1c
Merge pull request #5191 from p3n1cillin/claude/carry-chroot
feat(libkernel_sys): add chroot that keeps the guest root
2026-10-13 16:33:00 +02:00
Adrià 9dac817b19
Merge pull request #4548 from coltken95/fix/libc-printf-nan
fix(libc): print NaN without a sign in the guest printf formatter
2026-10-13 16:31:34 +02:00
Adrià c02df171c8
Merge pull request #4545 from thuanquang/test/tools-python39-hard-links
test(tools): create hard links with os.link for Python 3.9
2026-10-13 16:30:44 +02:00
Adrià 2672a73178
Merge pull request #4501 from devavijitsingh/fix/diagnose-self-module-skip
fix(relinker): warn when SELF modules are skipped
2026-10-13 16:30:12 +02:00
Nixitov 0f73f5f057 feat(libkernel): report the host SoC and CPU temperature
PPSA99058 and PPSA99420 import sceKernelGetCpuTemperature and sceKernelGetSocSensorTemperature and stop at start-up on main. Read the host CPU/package, board and NVMe sensors (hwmon/thermal on Linux, the ACPI thermal zones and the storage temperature property on Windows) and report an unsupported sensor with EINVAL.
2026-10-13 16:30:07 +02:00
Adrià 80e70b4292
Merge pull request #4408 from santhoshkumar-dev/codex/agc-render-target-vertex-aliasing
fix(agc): exclude skipped vertex records from target alias checks
2026-10-13 16:29:52 +02:00
Adrià b0d41be1ff
Merge pull request #4283 from MarcZX100/codex/carry-guest-thread-stacks-3283
fix(libkernel): place Linux guest thread stacks inside application area
2026-10-13 16:28:18 +02:00
MiniRML a8a78ded96 fix(progress): load the tokenizer beside the source file 2026-10-13 16:27:51 +02:00
MiniRML f37eecfdac fix(progress): ignore C++ raw-string contents 2026-10-13 16:27:51 +02:00
Adrià ef42c5f2af
Merge pull request #5183 from p3n1cillin/claude/carry-clock-settime
feat(libkernel): add clock_settime with FreeBSD argument checks
2026-10-13 16:27:05 +02:00
eljackjoestar-cmd 13818efc3b fix(agc): preserve array slice XOR in color target views 2026-10-13 16:25:05 +02:00
screamm f8a269e80a
feat(libkernel_sys): let chroot keep the guest root
Porpoise (PPSA99764) stops on its weak chroot import (#3632, #4497).
Run 5 on main c2565f014, and again on a copy of that runtime:

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

Its only call is in put_root_back (src/porpoise_jailbreak.cpp,
elripalda/Porpoise-Dolphin-Emulator-for-PS5 2ed1ab5a06995aa1): after a
jailbreak daemon has made the console's root its root and /app0 is
gone, it calls fchdir on the descriptor of "/" it opened at start, then
chroot("."), and checks the result. So it only ever puts back the root
it started in, and it does not use paths under any other root.

On top of the lookup errors of the previous commit, chroot now follows
FreeBSD 11.4 sys_chroot and pwd_chroot (8c639945, vfs_syscalls.c and
kern_descrip.c) for that case: a directory that is the guest root
("/", "/..", "." after fchdir to "/") succeeds without a change, since
fd_rdir would be set to the vnode it already is. The guest is taken
never to have changed its root, so with chroot_allow_open_directories 1
an open directory does not give EPERM. ENAMETOOLONG is added as in
pathconf, and a ".." through a file reports ENOTDIR instead of
escaping as a filesystem_error. Any other directory still throws: the
resolver's root and mount aliases are fixed, and no title is known that
needs a real new root.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 19:54:29 +05:30
screamm 7e5bec09f8
feat(libkernel_sys): add chroot with FreeBSD lookup errors
Porpoise (PPSA99764) imports chroot (AKknh8Cx-V8) from
libkernel_sys.prx, not libkernel.prx, one reference. Predicted stop
once pathconf, the pthread_attr calls and ftrylockfile ahead of it are
covered (not a run):

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/kern/vfs_syscalls.c sys_chroot and change_dir
(8c639945a44588f6cfdddfb057bb5aad88735da0) for a root caller up to the
lookup: EFAULT for a null path, ENOENT for an empty or missing one,
ENOTDIR for a file or a path through a file. A directory that is found
throws with the path named: the resolver's root is fixed and the mount
aliases (/app0, /savedata0) are host paths that do not move with it,
so it cannot be re-based, and a real chroot is not modelled. Nothing
shows that Porpoise calls it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 19:54:29 +05:30
TideOPL de5279bc0c fix(shader): serialize the pixel layer export flag from request version 23
main allocates request version 22 to the tessellation patches per group, so a version 22 request has no layer export byte.
2026-10-13 15:23:21 +01:00
Adrià 146f171549
Merge pull request #4271 from eljackjoestar-cmd/codex/reclaim-source-ir
perf(shader): reclaim unreachable cached source IR values
2026-10-13 16:22:26 +02:00
saxopa b3fa9d8318 fix(relinker): move the Linux program header table when it has no free slot
Linux output reused the input program header table in place, so it could
hold no more entries than the input declared. A title whose kept segments
and the five synthetic headers did not fit lost PT_GNU_EH_FRAME with a
warning, or failed with "Not enough program header slots". When more
headers are needed, the table is now written at the end of the extra block,
e_phoff points there and PT_PHDR maps it through the extra block PT_LOAD;
the header block then maps only the ELF header. Bytes after the input table
are left as they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:20:00 +02:00
Daan Dehing a910dee09f fix(agc): wait for recorded writes over a sampled texture's DCC keys before reading them
textureClearKeys reads the keys through a raw pointer, past the flush hook, so writes the
recorder holds for the key range are not in the bytes yet. A title that clears the keys of a
target with a kernel and samples it in the same batch had its keys read from the memory's
previous contents: in Palworld (PPSA23126) these were the float data of a reused heap, so the
keys read as mixed and the texels were read as stored.

When the keys read do not decode (not uncompressed, not a clear the format can fill),
WaitForKeyWriters answers from the pending fills and stores it knows, or waits for the batch
that writes the keys, and the keys are read again. Keys that decode are used as before.

RunSampledKeysBehindKernel (agc_driver_dcc_keys_first_write): key memory holding float bytes,
then the 0000 clear kernel recorded without a wait; the sampled texture's keys read Clear0000.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:18:50 +02:00
Adrià 759c66564f
Merge pull request #4428 from hypermoist/perf/address-space-import-runs
perf(agc): keep adjacent ranges one import serves as one region of the cached address space
2026-10-13 16:18:14 +02:00
Alexej Szpevák fc8165e8b9
test(cli): cover module-dir, sce-module-path and target option errors
Add parser tests for --module-dir, --sce-module-path, --macos and
--to-rosetta, including their repeat and conflict errors, which had no
coverage.
2026-10-13 16:17:23 +02:00
TideOPL 7015c0443e fix(shader): read the ancillary render target index from Layer when the draw exports it 2026-10-13 15:15:55 +01:00
Adrià 5d7f1ffc1c
Merge pull request #4217 from Mouad-Scriptz-0/feat/videoout-mouse-capture
feat(libSceVideoOut): capture the host cursor for guest mice and scale their deltas
2026-10-13 16:15:45 +02:00
Adrià ac6d1b2013
Merge pull request #4163 from Celegans12/feat/agc-tessellation-patch-inputs
feat(agc): read hull patch constants in tessellation domain programs
2026-10-13 16:15:23 +02:00
Adrià Franch 603d94a53f test(libkernel_sys): reuse longName in the fchmodat check 2026-10-13 16:14:56 +02:00
Nixitov e3c1d01815 feat(libkernel_sys): implement fchmodat
2 Ship 2 Harkinian (PPSA99621) imports fchmodat through std::filesystem::permissions and stops at start-up on main. Resolve AT_FDCWD and absolute paths as usual and join other relative paths to the directory descriptor like openat, accept 0 and AT_SYMLINK_NOFOLLOW, and mask the mode to 07777.
2026-10-13 16:14:53 +02:00
codingreapermaps 3953a8d49e feat(libc): record traced import calls on Windows
TraceImport_nid_no_patch wraps a function of a library named in
APS5_TRACE_CALLS in a thunk that records the import, the thread and
the caller in a ring and counts the call, then jumps to the function.
One target keeps one thunk, so function pointers compare equal. The
crash and abort reports print the last 64 calls and the 32 most called
imports. Nothing calls TraceImport_nid_no_patch yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:13:12 +02:00
Adrià 8c772ad342
Merge pull request #4265 from fisherjoey/fix/fiber-host-stack
fix(libSceFiber): run fibers on host stacks with room for host calls
2026-10-13 16:12:14 +02:00
Adrià ab1755c258
Merge pull request #4459 from LeandroLP23/docs/contributing-gpus-tested
docs(contributing): ask GPU changes to name the GPUs their tests ran on
2026-10-13 16:11:54 +02:00
screamm 41b0ca597b feat(libkernel_sys): let chroot keep the guest root
Porpoise (PPSA99764) stops on its weak chroot import (#3632, #4497).
Run 5 on main c2565f014, and again on a copy of that runtime:

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

Its only call is in put_root_back (src/porpoise_jailbreak.cpp,
elripalda/Porpoise-Dolphin-Emulator-for-PS5 2ed1ab5a06995aa1): after a
jailbreak daemon has made the console's root its root and /app0 is
gone, it calls fchdir on the descriptor of "/" it opened at start, then
chroot("."), and checks the result. So it only ever puts back the root
it started in, and it does not use paths under any other root.

On top of the lookup errors of the previous commit, chroot now follows
FreeBSD 11.4 sys_chroot and pwd_chroot (8c639945, vfs_syscalls.c and
kern_descrip.c) for that case: a directory that is the guest root
("/", "/..", "." after fchdir to "/") succeeds without a change, since
fd_rdir would be set to the vnode it already is. The guest is taken
never to have changed its root, so with chroot_allow_open_directories 1
an open directory does not give EPERM. ENAMETOOLONG is added as in
pathconf, and a ".." through a file reports ENOTDIR instead of
escaping as a filesystem_error. Any other directory still throws: the
resolver's root and mount aliases are fixed, and no title is known that
needs a real new root.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:11:08 +01:00
screamm dc0d316fda feat(libkernel_sys): add chroot with FreeBSD lookup errors
Porpoise (PPSA99764) imports chroot (AKknh8Cx-V8) from
libkernel_sys.prx, not libkernel.prx, one reference. Predicted stop
once pathconf, the pthread_attr calls and ftrylockfile ahead of it are
covered (not a run):

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/kern/vfs_syscalls.c sys_chroot and change_dir
(8c639945a44588f6cfdddfb057bb5aad88735da0) for a root caller up to the
lookup: EFAULT for a null path, ENOENT for an empty or missing one,
ENOTDIR for a file or a path through a file. A directory that is found
throws with the path named: the resolver's root is fixed and the mount
aliases (/app0, /savedata0) are host paths that do not move with it,
so it cannot be re-based, and a real chroot is not modelled. Nothing
shows that Porpoise calls it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:11:08 +01:00
Yunus Shaikh 6a46563a93 refactor(savedata): clear the mount result once the mount point is made
#5173 changes the create condition right after the last error check, and #3950 removes the comment after the create block, so clearing the result in either place made the pull requests conflict. The result is still cleared only after every error return and before anything is written to it.
2026-10-13 07:10:41 -07:00
Adrià 91ed4ce625
Merge pull request #5174 from AkulTyagi11/feat/libc-implement-powidf2
feat(libc): implement __powidf2
2026-10-13 16:09:23 +02:00
Mouad-Scriptz-0 94087d08b0 feat(libSceVideoOut): capture the host cursor for guest mice and scale their deltas
The console's mouse reports relative motion, so the host cursor can never line
up with the cursor a title draws. While a title has a mouse open and the
window is focused the host cursor is hidden and captured, released on focus
loss or while the pad's mouse-to-stick toggle is on. Motion deltas are scaled
from the presented image's size in window units to the title's display
resolution with sub-pixel carry, so the title's cursor travels as far as the
host pointer would, on scaled desktops and letterboxed windows alike.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 14:05:52 +00:00
Tomás Ortellado f0da9edbfe fix(relinker): reject overflowing LSDA landing pad addresses 2026-10-13 11:05:22 -03:00
Adrià d0711248b1
Merge pull request #4279 from karanvora2599/fix/shader-coherent-gds
fix(shader): declare the GDS buffer coherent
2026-10-13 16:04:55 +02:00
Adrià Franch 745857448e test(libkernel): check the host-only stack guard on Linux only
Windows guest threads keep their normal stacks, so there is no host-only guard page below the guest stack to query.
2026-10-13 16:03:39 +02:00
MarcZX100 9b6e7f66c4 fix(libkernel): protect host-only guest stack pages 2026-10-13 16:03:36 +02:00
Cesar Rodriguez 7637cac13e fix(libkernel): place guest thread stacks inside the application area
On Linux, glibc maps the stack of every guest thread near the top of the
host address space (around 0x7fff00000000). On the console, application
stacks lie inside the application area below 0xFC00000000, and guest code
relies on that: ChakraCore's garbage collector indexes a 4 MiB table with
address >> 18, so it only covers addresses below 1 TiB and reports
Js::OutOfMemoryException for a stack above it.

Map each guest thread's stack with DoMapAnon, which allocates from the
guest arena, behind a PROT_NONE guard page, and pass it to pthread_attr_setstack.
The stack is freed after a join; the stack of a detached thread is freed once its
host thread is gone from /proc/self/task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:03:36 +02:00
Adrià e0263e2b87
Merge pull request #5065 from MarcZX100/codex/cxa-thread-atexit
fix(libc): export __cxa_thread_atexit
2026-10-13 16:03:19 +02:00
milescoviello 0d30059bf5 fix(libkernel): handle FIOCLEX and FIONCLEX in ioctl
ioctl() on a file, directory, pipe or character device threw "request
0x20006601 ... is not implemented" for FIOCLEX, and the same for
FIONCLEX, although the close-on-exec flag they change is already kept
for these descriptors and reported by fcntl(F_GETFD).

FreeBSD 11.4 handles both requests in kern_ioctl() for every descriptor,
before the request reaches the file's own ioctl, by changing the flag
F_GETFD reads. sys/kern/sys_generic.c, kern_ioctl():

	case FIONCLEX:
		fdp->fd_ofiles[fd].fde_flags &= ~UF_EXCLOSE;
		goto out;
	case FIOCLEX:
		fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE;
		goto out;

sys/kern/kern_descrip.c, kern_fcntl():

	case F_GETFD:
	...
			td->td_retval[0] =
			    (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0;

Both requests now set or clear that flag and return 0. libuv before 1.44
sets close-on-exec this way on FreeBSD (uv__cloexec_ioctl).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:59:42 +01:00
nabilfp ae9978a98e feat(libkernel): add clock_settime with FreeBSD argument checks
PS5MC (PPSA99420, Kodi 22) imports clock_settime (d7nUj1LOdDU) from
libkernel.prx, one reference, after sigwaitinfo in its import order.
Predicted stop once the imports ahead of it are covered (not a run):

  FAIL: unresolved ELF import d7nUj1LOdDU from libkernel.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/kern/kern_time.c sys_clock_settime and
kern_clock_settime (8c639945a44588f6cfdddfb057bb5aad88735da0) for a
root caller: EFAULT for a null time (copyin), EINVAL for any clock but
CLOCK_REALTIME and for a negative tv_sec or a tv_nsec outside 0 to
999999999. A valid CLOCK_REALTIME request throws with the requested
time named, since the host clock must not be set and no guest clock
offset is kept.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Co-authored-by: David <david@example.com>
2026-10-13 14:57:46 +01:00
p3nicillin 72a685b906 feat(libkernel): report _SC_CLK_TCK through sysconf
The Python in PS5MC (PPSA99420) reads sysconf(_SC_CLK_TCK) while
importing its posix module and failed with "cannot read
ticks_per_second". It returns FreeBSD's CLK_TCK, 128.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:53:24 +01:00
Mouad-Scriptz-0 326e0bc29f fix(agc): raise the graphics end-of-pipe event when a flip completes
A flip packet now delivers the queue's end-of-pipe event once the work
recorded before it completes, as a RELEASE_MEM with INT_SEL does. Minecraft
(PPSA17221) registers the graphics event, never requests an interrupt in its
releases, and waits on the event after every flip while holding its render
lock, so it presented one frame and then waited forever.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:49:45 +02:00
Adrià Franch 7a8e1b2559 docs(debt): restore UTF-8 characters corrupted in shader.md
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:48:15 +02:00
eljackjoestar-cmd 57b2dc8584 perf(shader): reclaim unreachable cached source IR values 2026-10-13 15:48:04 +02:00
Adrià e152ba8f69
Merge pull request #4209 from karanvora2599/fix/shader-cube-gradients
fix(shader): keep cube image gradients out of the face coordinate bias
2026-10-13 15:45:43 +02:00
Adrià 6cd052848a
Merge pull request #4210 from karanvora2599/fix/agc-depth-before-shader
fix(agc): test depth before pixel shaders that ask for it
2026-10-13 15:44:24 +02:00
Karan Vora 0998eb4f23 fix(shader): declare the GDS buffer coherent
GDS is one memory for the whole GPU on AMD hardware: every work-group's
ds_read and ds_write with gds see the others' writes, with no cache in
between. The recompiler keeps it in a storage buffer that was not decorated
Coherent, so on a GPU whose L1 caches storage buffer loads, NVIDIA's from
Turing on among them, a plain GDS read could return a value cached before
another work-group's GDS write. Atomics were not affected. The gds buffer is
now declared Coherent.

verifyCoherentGds in agc_shader_memory compiles a ds_read_b32 and a
ds_write_b32 on GDS and checks that the gds buffer is Coherent.
2026-10-13 15:43:31 +02:00
Adrià 2cf23fcc56
Merge pull request #4114 from Celegans12/fix/agc-tessellation-num-patches
fix(agc): bound tessellation patch records by the draw's patch count
2026-10-13 15:40:48 +02:00
Adrià 6c0f83c7cf
Merge pull request #4211 from karanvora2599/perf/shader-bindless-table-once
perf(shader): search a bindless image table once per access
2026-10-13 15:39:50 +02:00
Adrià Franch 36eb627051 fix(libSceFiber): throw when a fiber's host stack cannot be set up
No fallback to the title's context: a failed mmap or mprotect throws,
as on Windows.
2026-10-13 15:37:30 +02:00
fdfawef324 81364388a0 fix(libSceFiber): run fibers on host stacks on Windows
#4265 gives each fiber an mmap'd host stack on Linux and leaves Windows
as it was: there a fiber still runs host calls inside the context the
title passed to sceFiberInitialize. Demon's Souls packs its 16 KiB job
fiber contexts back to back. A job that calls
sceAgcCreateInterpolantMapping reaches shader preparation on the fiber
(Driver::ResolveShaderAbi, PrepareRegistered, the RDNA decoder,
BuildShaderStageInputInfo), goes more than 16 KiB deep and overwrites
the frames at the top of the context below it. On the loading screen
after the opening cinematic the fiber that owns that context then
failed the title's stack check, or returned to 0x7fffffff.

On Windows each fiber now gets a host stack from VirtualAlloc, the
context size plus 1 MiB, committed like the 1 MiB host margin of guest
threads, with a PAGE_NOACCESS page at the bottom. While the fiber runs,
the TIB stack base and limit and the deallocation stack describe that
host stack, as Windows does for its own fibers, so stack probes and
GetCurrentThreadStackLimits see the stack the fiber runs on. A host
stack that cannot be allocated, protected or released throws instead
of falling back to the context.

agc_driver_gpu_map_on_fiber: GetCurrentThreadStackLimits on a fiber now
returns its host stack, which has room for the import, so on Windows a
GPU mapping made on a fiber imports on the fiber's stack instead of a
host thread. The fiber's context is still not written.

Test: on Windows, fiber checks that the TIB stack bounds inside a fiber
cover its host stack, at least the context plus 256 KiB. With #4265
alone it fails at "the thread's stack bounds are the fiber's host
stack", and without that check at "a host call from a 16 KiB fiber
writes nothing below its context"; with this change fiber and
agc_driver_gpu_map_on_fiber pass (Windows Server 2025, RTX 3060,
WinLibs GCC 15.2.0, Release).

Demon's Souls (PPSA01342) on that host: at the loading screen the two
16 KiB job fibers above the overwritten one now use 17,592 and 16,936
bytes of their host stacks, the title's stack check no longer fails
there, and the load goes on until a separate Vulkan allocation failure
(vkAllocateMemory of a 4 MiB host-visible buffer, out of device memory).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:37:23 +02:00
Joey Fisher 794714983c fix(libSceFiber): run fibers on host stacks with room for host calls
Host code that a guest fiber calls runs on the fiber's stack. Demon's
Souls (PPSA01341) gives its job fibers 16 KiB contexts packed next to each
other, and a fiber that reaches shader preparation through
Driver::ResolveGraphicsStagesAbi goes about 21 KiB deep when SPIRV-Tools
validates the module. That overwrites the saved frame of the fiber below,
and the next switch to that fiber pops garbage into rbp, rbx, r12-r15 and
rip (a jump to 0x1a in the observed crash).

Fibers now run on an mmap'd host stack of the context size plus 1 MiB,
with a guard page at the bottom, the same margin guest threads get since
#2647. The guest context is no longer written. Context size checks fill
and scan the top context-size bytes of the host stack, so
size_context_margin keeps its meaning. If the mapping fails the fiber
runs in its context as before. Windows is unchanged: it pins and
publishes the guest context as the stack, and that path is not covered
here.

The fiber test now runs a 256 KiB host call from a 16 KiB fiber placed at
the top of a guard-filled area and checks nothing below the context was
written. It fails on main.
2026-10-13 15:37:23 +02:00
Adrià 58f7242ea2
Merge pull request #3934 from MarcZX100/codex/carry-setlocale-category
fix(libc): reject invalid setlocale categories
2026-10-13 15:35:56 +02:00
Adrià 3a60a0d054
Merge pull request #4011 from karanvora2599/perf/shader-f16-compare-any-nan
perf(shader): skip the f16 NaN rebuild for operands that are only compared
2026-10-13 15:34:02 +02:00
Adrià Franch 1ab578a3f7 test(libc): allow the __cxa_thread_atexit export to call the MinGW registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:33:28 +02:00
Adrià Franch 9c383e3295 fix(libc): ignore the guest DSO of thread atexit on Windows in the shared bridge
MinGW's __cxa_thread_atexit asserts dso is null or its own __dso_handle, so every guest export that forwards a guest module pointer needs the null rule, not only LibcInternalExtCxaThreadAtexit. The test now passes a non-host DSO on Windows too.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:33:22 +02:00
MarcZX100 90c64af925 fix(libc): export __cxa_thread_atexit 2026-10-13 15:33:22 +02:00
Adrià 0c05d3cfc7
Merge pull request #4105 from MarcZX100/codex/carry-execv-execve-3558
feat(libkernel): add execve as a throwing export
2026-10-13 15:31:29 +02:00
Akul Tyagi b4e2ee0a13 feat(libc): implement __powidf2
The H+8UBOwfScI import was a throwing stub (libcCyberUnknown08). It is
the NID of "__powidf2", the double-precision integer-power helper that
complements __powisf2.
2026-10-13 19:00:24 +05:30
Adrià 5b08344585
Merge pull request #3907 from GalaxyGamingFR/fix/progress-read-encoding
fix(progress): read cmake and shader tables as utf-8
2026-10-13 15:27:02 +02:00
Adrià Franch 3973e5ad77 docs(technical-debt): record the hardware measurement of cube image gradients
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:26:05 +02:00
Karan Vora 73eaa1f18b fix(shader): keep cube image gradients out of the face coordinate bias
image_sample_d and image_sample_cd on a cube pass their gradients through the
same conversion as the face coordinates, which subtracts 1.0 to move AMD's
[1, 2] face range to [0, 1]. A gradient is a difference of coordinates, so the
bias turned a one-texel gradient into one of about -1 and the sample read the
smallest mip. Gradients now skip the bias.

agc_driver_image_sample_cube_derivatives samples every face of a 16x16 cube at
five levels through image_sample_d and checks the level and face it read.

TechnicalDebt records that the gradient handling follows Mesa and was not
measured on hardware.
2026-10-13 15:26:04 +02:00
Adrià e22a77eba2
Merge pull request #3901 from GalaxyGamingFR/fix/conventions-agent-file-case
fix(conventions): match agent instruction files case-insensitively
2026-10-13 15:26:01 +02:00
Adrià 3faa9cb400
Merge pull request #5103 from ErenYeager1836/carry/audioout-enable-chat
feat(libSceAudioOut): implement sceAudioOut2EnableChat
2026-10-13 15:22:57 +02:00
Adrià a252fcd75f
Merge pull request #4012 from queeeef/perf/agc-zero-dword-fill
perf(agc): handle the zero dword fill kernel as a buffer fill
2026-10-13 15:21:00 +02:00
Adrià Franch b81ababfc6 docs(technical-debt): record DEPTH_BEFORE_SHADER in debt/libSceAgcDriver.md 2026-10-13 15:19:51 +02:00
Karan Vora 320bd37c92 fix(agc): test depth before pixel shaders that ask for it
DB_SHADER_CONTROL.DEPTH_BEFORE_SHADER (bit 12) is what a pixel shader compiled
for early depth/stencil sets: the depth and stencil tests and writes happen
before the shader runs, even when it kills pixels or writes memory. The bit
was accepted but never read, so such shaders got EarlyFragmentTests only when
Z_ORDER was EARLY_Z_THEN_LATE_Z and they had no kill or exports. Their killed
pixels then left depth unwritten, and occluded pixels still wrote memory.
EARLY_Z_THEN_RE_Z (Z_ORDER 3) was not treated as early either.

DecodePixelStageInfo now sets earlyZ for DEPTH_BEFORE_SHADER, and for Z_ORDER
1 or 3 under the existing kill and export conditions, including the stencil
reference export. The backend no longer repeats those conditions; it keeps
only the alpha-to-coverage one, so a shader with alpha-to-coverage still runs
its tests late. earlyZ keeps its place in the request, so the serialization
version does not change.

earlyFragmentTestsTests in agc_driver_graphics checks which DB_SHADER_CONTROL
values declare EarlyFragmentTests, and that alpha-to-coverage keeps Z_ORDER 1
and DEPTH_BEFORE_SHADER late, directly and after a serialization round trip.
stencilRefExportTests checks that DEPTH_BEFORE_SHADER with a stencil reference
export still decodes as early.

TechnicalDebt records that the bit follows Mesa and that its combination with
a Z export, a mask export, a stencil export or alpha-to-coverage was not
measured.
2026-10-13 15:19:33 +02:00
Adrià Franch cdf4b174f4 fix(libkernel): keep the execv export and its debt line
The rename to execve dropped execv, which PPSA97358 imports.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:19:19 +02:00
MarcZX100 77016caa24 fix(libkernel): limit execve to unsupported behavior 2026-10-13 15:19:19 +02:00
David 4f1ae1cc3a feat(libkernel): implement execv and execve as throwing exports
XPSemu PPSA97358 imports both from libkernel.prx; with the imports ahead
of them covered, its predicted next stops (relink registry order, not an
observed run) are:

  FAIL: unresolved ELF import KaK52lYTBIs from libkernel.prx  (execv, 7 call sites)
  FAIL: unresolved ELF import kdguLiAheLI from libkernel.prx  (execve, 4 call sites)

Today the title stops earlier at the observed
  FAIL: unresolved ELF import aRo9AhFUXcM from libkernel.prx  (sigsetjmp, merged in #3486)

As for execvp (#2827), the process image cannot be replaced here, so both
throw with the execvp message pattern once FreeBSD 11's execve would start
loading the image (freebsd-src 8c639945, sys/kern/kern_exec.c
exec_copyin_args, do_execve, exec_check_permissions; lib/libc/gen/exec.c
execv passes environ). Before that they fail as FreeBSD does: EFAULT for a
null argument vector or path, ENOENT and ENOTDIR from the lookup as stat
reports it, EACCES for a path that is not a regular file. Paths of
PATH_MAX bytes or more and strings over ARG_MAX throw instead of guessing
the console's limits. The execv calls in XPSemu's sources run in a fork
child (net/tap.c), and its fork fails with ENOSYS (ZiZc3/XPSemu 8eec07b4,
ps5/compat/libc_missing.c, ps5/build-title.sh --defsym).

NIDs computed with tools/nid_names.py and confirmed in aerolib.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 57f0fa37132bc6c78bc02282044a00e2db859484)
2026-10-13 15:19:19 +02:00
xXPBSXx 79e162110a fix(libkernel): report SO_ERROR and the other SOL_SOCKET options like FreeBSD
getsockopt and setsockopt on a libkernel socket knew four SOL_SOCKET options
(SO_REUSEADDR, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF) and failed every other
one with ENOPROTOOPT. The Mound's EOS SDK reads SO_ERROR on two of its
sockets after a connect, which therefore always failed.

The SOL_SOCKET options now follow FreeBSD 11.4 sosetopt and sogetopt:
- SO_ERROR returns the pending error of the socket as a FreeBSD errno and
  reports it once (Winsock does not clear it on read, so the library does).
- SO_TYPE, SO_ACCEPTCONN, SO_KEEPALIVE, SO_DONTROUTE, SO_OOBINLINE and
  SO_LINGER are read from and set on the host socket; the boolean options
  read back as their own bit, as FreeBSD returns so_options & option.
- SO_DEBUG, SO_USELOOPBACK, SO_REUSEPORT, SO_TIMESTAMP and SO_NOSIGPIPE stay
  ENOPROTOOPT until a title needs one.
- A value is read from its first int and fails with EINVAL when shorter, a
  getsockopt buffer is filled up to its length (sooptcopyin, sooptcopyout),
  SO_SNDBUF and SO_RCVBUF below 1 fail with EINVAL, and SO_LINGER outside
  0..65535 seconds fails with EDOM.

A connect on a non-blocking socket now fails with EINPROGRESS on Windows too
(it was EWOULDBLOCK, which a title waiting for the connection does not
expect).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 15:18:29 +02:00
Adrià 6ac63bf0cb
Merge pull request #5104 from Feuris/feat/libc-wcscat
feat(libc): implement wcscat
2026-10-13 15:18:07 +02:00
Adrià 5aaa394cff
Merge pull request #5080 from ErenYeager1836/carry/libSceAgc-amm-semaphore
feat(libSceAgc): implement sceAgcSetAmmSemaphoreMemory and sceAgcGetSemaphoreLabel
2026-10-13 15:17:12 +02:00
Adrià 1e7f4967ed
Merge pull request #3743 from YossiYad/carry/ampr-pad-launch
feat(libSceAmpr): implement the std::_Pad thread launch helpers
2026-10-13 15:15:37 +02:00
Adrià 21bdab007a
Merge pull request #1312 from TibixDev/pr/incremental-draw-fingerprints
perf(agc): maintain draw fingerprints on register writes
2026-10-13 15:15:17 +02:00
Adrià Franch 1a0de9e91f fix(libc): drop unused clocale include
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:13:01 +02:00
MarcZX100 2ec20dbd37 fix(libc): validate guest setlocale categories 2026-10-13 15:12:57 +02:00
MarcZX100 5eb99f8b65 fix(libc): reject invalid setlocale categories
(cherry picked from commit 099fa80b53eba577d29a0bfff672dc4f9c160ec1)
2026-10-13 15:12:56 +02:00
Karan Vora 352bf304fe perf(shader): skip the f16 NaN rebuild for operands that are only compared
With float16DenormPreserve, EmitF16BitsToF32 rebuilds the bits of a NaN
half after UnpackHalf2x16, because NVIDIA returns the default NaN and
Intel quiets it. When every use of the converted operand is an f32
comparison or a NaN test, directly or through abs and neg, only whether
it is NaN matters, so the conversion returns UnpackHalf2x16's result as
is. v_cmp_*_f16 goes from 11.5 to 4 SASS on an RTX 4060.

agc_driver_f16_to_f32_unpack adds v_cmp_u_f16 and v_cmp_lt_f16 over all
65,536 halves with each decode the device supports. Its SPIR-V check
requires the v_cvt_f32_f16 conversion to rebuild the NaN bits and the
compared conversions not to.
2026-10-13 15:11:54 +02:00
Aarav 2f453805aa fix(libSceSystemService): contain converted executable paths 2026-10-13 18:40:19 +05:30
Adrià c98fda869a
Merge pull request #4015 from sherySJ/agent/libc-time-eoverflow
fix(libc): keep the caller errno when localtime cannot represent a time
2026-10-13 15:10:07 +02:00
Adrià 4008e68e39
Merge pull request #3919 from GalaxyGamingFR/fix/stubgen-stdout-newlines
fix(stubgen): write LF to stdout on Windows
2026-10-13 15:09:35 +02:00
Adrià d5835a613b
Merge pull request #5102 from Dripl1x/codex/generic-error-category
feat(libc): implement generic error category messages
2026-10-13 15:08:29 +02:00
Adrià Franch 76075edd38 test(libSceAudioOut): define TestEnableChat; drop stale EnableChat unknown-signature line
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 15:06:32 +02:00
screamm 50cd318bb8 feat(libSceAudioOut): implement sceAudioOut2EnableChat
Palworld (PPSA23126, #2648) stops at start-up on the export, imported by
its bundled libdiscord_partner_sdk.prx:

    FAIL: unresolved ELF import oiOi7vgPfAY from libSceAudioOut.prx

PPSA28416 imports it from its bundled party-ps5-shipping.prx as well. The
call itself has not been observed yet.

SharpProspero (5dfdb4b0, Interop/Audio/AudioOut2.cs:460-464) declares
`int sceAudioOut2EnableChat()`, "Allows chat audio alongside the
application's own", and the ps5-payload-dev SDK stub (f5d40f02,
sce_stubs/libSceAudioOut.c:62) exports it as well. There is no context or
handle to validate. The host mixes no chat audio and AudioOut2 has no chat
port, so the call records that chat audio is allowed (traced once with
APS5_TRACE_AUDIOOUT2) and returns 0. Whether the console fails it without
a chat session or when repeated is recorded in technical debt, and the
PPSA28416 "signature unknown" entry is dropped.

NID oiOi7vgPfAY matches tools/nid_names.py and the shadPS4 aerolib list.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:06:27 +02:00
Adrià Franch 6ba5d68e07 docs(debt): move the AMM semaphore line away from the end of Functional 2026-10-13 15:01:48 +02:00
David 352d04e8dc feat(libSceAgc): implement sceAgcSetAmmSemaphoreMemory and sceAgcGetSemaphoreLabel
sceAgcSetAmmSemaphoreMemory(memory, sizeInBytes) registers the AMM semaphore memory once and zeroes the first 8 bytes of each 32-byte label; sceAgcGetSemaphoreLabel(index, label) writes memory + 32 * index for an index inside the registered memory.

Unblocks New Joe & Mac Caveman Ninja (PPSA02801) which imports both symbols. Matches OpenAGC and sharpemu agreements on signatures, 16 KiB alignment, 32-byte stride, and zeroed label counters.
2026-10-13 15:01:43 +02:00
Kikoarl e5f0938409 feat(ces): implement sceCesUcsProfileInitSJis1997Cp932 2026-10-13 15:00:31 +02:00
Yossi Yadgar dd1deb6965 fix(ampr): raise std::_Pad failures as the guest std::system_error
A failing _Pad primitive threw a host std::runtime_error, which no guest
catch can see. threadcall.cpp calls the checked wrappers of xthread
(_Mtx_lockX, _Cnd_waitX, _Thrd_startX), which pass a non-success code to
_Throw_C_error: _Thrd_nomem and _Thrd_timedout become
resource_unavailable_try_again, _Thrd_busy device_or_resource_busy and
_Thrd_error invalid_argument, raised through _Throw_Cpp_error, which main
now implements. A failing thread start is _Thrd_startX's
resource_unavailable_try_again.

_Release now wakes the launching thread with _Cnd_signal, as
threadcall.cpp does; libc has it since the pad was written.

guest_ampr_threads checks, in a forked child whose guest terminate
handler reports the thrown object, that _Release on the thread still
holding the pad's mutex throws std::system_error with EBUSY. It fails
with the previous host exception and with busy mapped to
invalid_argument.
2026-10-13 15:59:28 +03:00
melihcan 0afa191660 test(libSceConvertKeycode): cover sceConvertKeycodeGetImeKeyboardType
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:59:08 +02:00
xXPBSXx c6a4223420 fix(agc): sample 10_10_10_2 SNorm and SInt textures
Guest texture formats 51 (SNorm) and 55 (SInt) of the 10-bit packed group were missing from the texture lookup and the descriptor format table, so a descriptor using them threw 'unsupported guest texture format' while the UNorm (50) and UInt (54) siblings worked. Map them to A2B10G10R10_SNORM_PACK32 / A2B10G10R10_SINT_PACK32, classify them for sampling (float / signed integer), and list SINT among the integer formats.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 14:56:03 +02:00
Aarav 6f0f7c7461 fix(relinker): reject relocatable ELF conversion inputs 2026-10-13 18:23:31 +05:30
Yossi Yadgar 8e3b2a06f2 fix(ampr): exclude the private pad entry from the export inventory 2026-10-13 15:51:00 +03:00
Yossi Yadgar 49d8cf3e61 test(ampr): exercise simultaneous pad launches and destroyed storage 2026-10-13 15:51:00 +03:00
David d991cdccf9 feat(libSceAmpr): implement the std::_Pad thread launch helpers
Implement _ZNSt4_PadC2Ev, _ZNSt4_PadD2Ev, _ZNSt4_Pad7_LaunchEPP7pthread
and _ZNSt4_Pad8_ReleaseEv, which Deathloop (PPSA01670) and Minecraft
Legends (PPSA05510) import from libSceAmpr for the std::thread launch path.

The algorithm and object layout follow Dinkumware V6.00 thr/xthread and
thr/threadcall.cpp of Visual C++ 2013 (ganboing/crt.vc12 f1d47126): a
vtable pointer whose first slot is the pure virtual _Go(), then the
condition and mutex handles and bool _Started (0x8, 0x10, 0x18), with the
console's pointer-to-slot handles of libc Threads.cpp (#3079). The pad
uses libc's _Cnd_*/_Mtx_* exports, starts the guest thread with
pthread_create and an entry that calls _Go() and returns its result as
the exit code, as _Call_func does. The unverified layout, thread
attributes and error reporting are recorded in TechnicalDebt.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:51:00 +03:00
Adrià Franch a37ee5ff2c fix(libc): keep the caller errno when the Windows tm_year range overflows
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 14:50:07 +02:00
sherySJ b1cf01464a fix(libc): keep the caller errno when localtime cannot represent a time 2026-10-13 14:50:03 +02:00
Adrià Franch dd49e1df93 build(agc): put libc's directory on PATH for the register key test on Windows
The sibling AGC driver tests get this through the agcTest loop; without it the test exits 0xc0000135 (DLL not found) on Windows.
2026-10-13 14:49:31 +02:00
Adrià Franch 89414d3039 build(agc): link register key test with libc and libkernel like its sibling tests
The Windows build failed to start it (0xc0000135, DLL not found).
2026-10-13 14:49:24 +02:00
TibixDev 5942b8c7f1 perf(graphics): track draw register fingerprints incrementally
Track mutations against the current draw dependency mask and preserve device and shader registry identity in the draw key. Validate mutations, projected masks, PM4 packets and prepared graphics against full recomputation.

Written with AI assistance.
2026-10-13 14:49:24 +02:00
GalaxyGamingFR 1c32fd93c8 fix(progress): read cmake and shader tables as utf-8
scan_library and collect_shaders read CMakeLists.txt, the ISA table and the opcode header with the locale codec. On Windows that is cp1252, so a UTF-8 file containing U+2010 or U+2192 raised UnicodeDecodeError. These reads now pass encoding="utf-8" and errors="ignore", and a subprocess test with an ASCII default codec covers it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 14:48:50 +02:00
GalaxyGamingFR b12d6f5394 fix(conventions): match agent instruction files case-insensitively
The repository check compared the file name to a lower-case set, so a
file added as CLAUDE.md, Agents.md or GEMINI.md passed the check while
claude.md was rejected. Compare the lower-cased name so every spelling
of an agent instruction file is reported.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 14:48:43 +02:00
screamm 8b9529b99a fix(libScePosixForWebKit): keep the getservbyname result trivially destructible
The per-thread servent storage held std::string and std::vector
members, so getservbyname_nid_postfix registered a thread_local
destructor through __cxa_thread_atexit. On Windows that destructor runs
after emulated TLS freed the object, and prx_thread_local_destructors
(#4029) rejects libScePosixForWebKit.prx for it.

The result now lives in a thread_local struct of fixed-size char arrays
and an alias pointer array, sized for the longest name (submission),
alias (www-http), protocol (sctp) and alias count in the embedded table;
static_asserts check the sizes against the table and that the struct is
trivially destructible. The guest servent layout and the per-thread
result FreeBSD's getservent.c keeps in its NSS TLS state are unchanged.
Nothing is allocated, so the ENOMEM path is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:43:05 +03:00
screamm 15bbc19501 feat(libScePosixForWebKit): implement getservbyname
Implement getservbyname (H1bArJPagV0) in libScePosixForWebKit. Cloud
Play (PPSA99600) imports it from this library only (registry index 408,
call site 0x1042124); once fnmatch (#3545) is in, its predicted load
stop is:

    FAIL: unresolved ELF import H1bArJPagV0 from libScePosixForWebKit.prx

The ps5-payload-dev SDK stubs (f5d40f02, sce_stubs/) declare
getservbyname in libScePosixForWebKit.c and not in libkernel.c or
libSceLibcInternal.c. The call site is the service-name branch of a
getaddrinfo inside the title: a non-numeric service is looked up with
protocol "tcp", "udp" or "sctp" and the port is read big-endian at
offset 16 of the result, which fixes the servent layout used here
(name, aliases, 32-bit port, protocol at 0, 8, 16, 24).

The guest has no /etc/services and the console's file is unknown, so the
function searches 37 lines of FreeBSD 11.4 etc/services (8c639945):
ftp-data, ftp, ssh, telnet, smtp, domain, tftp, http, pop3, ntp, imap,
https, rtsp, submission, imaps and pop3s with their aliases and
protocols, in file order. None of their names or aliases appears on an
earlier line of the full file, so these lookups answer as the full file
would. The search follows files_servent in lib/libc/net/getservent.c
(8c639945): exact, case-sensitive match on the name or an alias, a null
protocol takes the first match, the port in network byte order, the
result in per-thread storage like getserv's NSS TLS state. Any other
name returns null without touching errno, as for a name the file lacks.
The repository's getaddrinfo still resolves service names through the
host, so there was no table to share; this is recorded in
TechnicalDebt.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:43:05 +03:00
Avijit Singh 48ea54ed3e fix(relinker): include output stream header
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 18:05:37 +05:30
Avijit Singh 1796482721 docs(relinker): clarify skipped SELF modules
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 18:04:49 +05:30
Avijit Singh f23c5c2fd2 test(relinker): cover SELF skip warnings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 18:04:49 +05:30
Avijit Singh 82f24e44a2 fix(relinker): warn on skipped SELF modules
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-13 18:04:49 +05:30
Romans Pokrovskis 44c4b3f8bf fix(agc): admit inactive covered-centroid mode
Admit PA_SC_AA_CONFIG bit29 only without active perspective or linear centroid inputs, or with a skipped pixel program. Active/unspecified centroid inputs and unrelated AA fields remain refused. Source: pinned PS5_Mesa 0b2d6d1a GFX10.3 schema/RADV producer; existing ENA/ADDR intersection. Console covered-centroid interpolation remains unmeasured.

Full build/all 124 runtime libraries, conventions and registration pass. Final Windows suite: 965 pass, zero fail, seven skips of 972. Isolated state test passes 20 repeats and fails 5/5 with main State.cpp; four guard mutants fail 5/5 each. Original two title register captures reproduce the main refusal and pass this check with candidate, five times each. NVIDIA relevant groups pass; AMD draw-cache failure also occurs on unchanged main and is reported in issue4435.

AI-assisted: Codex.
2026-10-13 15:34:41 +03:00
boykopovar 0f2683cb7d
Merge pull request #5135 from boykopovar/feat/web-relinker-ui
feat(ci): add relinker wasm build ci
2026-10-13 15:31:28 +03:00
Adrià c827e11872
Merge pull request #4086 from hugodearaujo/fix/setschedparam-console
fix(libkernel): check and keep the scheduling policy of a thread
2026-10-13 14:29:15 +02:00
boykopovar 693578f116 ci(pages): rename deployment workflow file 2026-10-13 15:27:02 +03:00
Adrià afbc22fb1a
Merge pull request #4140 from veosett/fix/relinker-windows-fixed-base
feat(relinker): support fixed Windows guest image bases
2026-10-13 14:26:54 +02:00
Adrià 94d9957725
Merge pull request #4078 from MarcZX100/codex/carry-ssl-connections-3766
fix(libSceSsl): add missing verification callback export
2026-10-13 14:26:09 +02:00
boykopovar dece64c6e8 ci(pages): build and deploy wasm converter 2026-10-13 15:26:04 +03:00
Adrià a164b1d711
Merge pull request #1359 from TibixDev/pr/copied-write-ordering
fix(agc): order direct reads after copied writes
2026-10-13 14:25:22 +02:00
Aarav bc014a887c fix(relinker): reject load file sizes beyond memory size 2026-10-13 17:55:11 +05:30
SandstromPL d34b78890d fix(savedata): return no saves for a search with another title's ID
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:53:29 +05:30
Adrià 398ccaaf96
Merge pull request #5108 from adriadam10/ci/agc-graphics-tests-link-driver
build(agc): link the graphics and BDA device tests against libSceAgcDriver
2026-10-13 14:19:16 +02:00
Adrià bc0375c72a
Merge pull request #5130 from adriadam10/ci/windows-keep-f16-unpack
ci(windows): build the f16 unpack execution test, it runs without a device
2026-10-13 14:18:44 +02:00
Adrià a60f8d940b
Merge pull request #5048 from MarcZX100/codex/libc-openlog-closelog
fix(libc): implement openlog and closelog state
2026-10-13 14:18:31 +02:00
Adrià Franch 5181b30d79 ci(windows): build the f16 unpack execution test, it runs without a device
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 14:18:28 +02:00
boykopovar 8485298e46
Merge pull request #5114 from boykopovar/feat/web-relinker-ui
feat(pages): add web relinker ui
2026-10-13 15:16:10 +03:00
Adrià a2a3a3a94d
Merge pull request #4062 from danzaio/fix/windows-log-without-standard-handles
fix(relinker): log Windows output when standard handles are missing
2026-10-13 14:11:42 +02:00
Adrià 96f3e9fe5d
Merge pull request #4041 from ee6aba54/fix/agc-cmask-unknown-codes
fix(agc): keep the texels of CMASK tiles with codes other than 0 and 15
2026-10-13 14:11:16 +02:00
boykopovar 860cecf11e docs(readme): link online converter and simplify progress history 2026-10-13 15:03:17 +03:00
Adrià Franch 14f2092c9e build(agc): link the graphics and BDA device tests against libSceAgcDriver
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 13:53:51 +02:00
boykopovar dae5690e59 fix(web): reject windows folder output before writing files 2026-10-13 14:53:19 +03:00
Adrià 14036cb0e8
Merge pull request #5107 from adriadam10/ci/linux-mesa-shader-cache
ci(linux): keep lavapipe's shader cache between builds
2026-10-13 13:51:53 +02:00
Adrià Franch aef5972ff5 ci(linux): keep lavapipe's shader cache between builds
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 13:51:10 +02:00
Celegans12 247162dc4f feat(agc): read hull patch constants in tessellation domain programs
TessellationLowering refused every domain-program read of the off-chip
ring outside its patch's control points, so domain programs that read
the hull's patch constants, like the quad terrain domain in Ghost of
Yotei at 0x8000 - 208 * (rel + 1), aborted.

Such reads now lower to a new PatchInput kind and become Patch inputs.
Hull outputs and domain inputs place a constant by its off-chip address
modulo the record stride, in a record-sized array at location
ceil(hsStride / 16); each program derives both on its own, so the two
interfaces match although they compile separately. Domain reads at an
address that does not move with the relative patch, across more than
one record or inside the control-point region still throw, as does a
domain program that reads patch constants but no control point. Hull
patch-constant writes now take the same bound: above the control points
of all NUM_PATCHES patches, not just one patch's.
2026-10-13 13:50:53 +02:00
Celegans12 25a83722c7 fix(agc): bound tessellation patch records by the draw's patch count
TessellationLowering proved ring and LDS addresses affine over a
relative patch index of up to 256. A hull that lays its patch-constant
records out downwards, at 0x8000 - 208 * (rel + 1) like the quad
particle hull in Ghost of Yotei, then reached a negative address for
the last slot and aborted as "not affine". The relative patch index of
hull and domain programs stays below VGT_LS_HS_CONFIG.NUM_PATCHES
(bits 7:0, patches per threadgroup), which is 63 for that draw.

DecodeShaderStages now carries NUM_PATCHES as patchesPerGroup in the
tessellation configuration (draw keys, hull and domain cache keys,
recompile request version 22) and refuses zero, and the lowering bounds
the relative patch index by it. Configurations without it keep 256.
2026-10-13 13:50:27 +02:00
Adrià ff8fe4dbc1
Merge pull request #3988 from karanvora2599/perf/shader-f16-unpack-half
perf(shader): convert f16 operands with UnpackHalf2x16 where f16 denormals are kept
2026-10-13 13:48:59 +02:00
Adrià c63dd4442c
Merge pull request #5106 from adriadam10/ci/agc-mesh-tests-link-driver
build(agc): link agc_driver_mesh_tests against libSceAgcDriver
2026-10-13 13:47:54 +02:00
Adrià Franch f20a32bec3 build(agc): link agc_driver_mesh_tests against libSceAgcDriver
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 13:46:45 +02:00
Dean ce8f7eeb3f
Merge pull request #4344 from Roojool/contrib/round2-c19
fix(tools): use configured Ninja for test registration audit
2026-10-14 00:46:35 +13:00
Adrià 84e2a8c0b3
Merge pull request #5105 from adriadam10/ci/windows-device-test-stubs
ci(windows): build only the execution tests that run without a Vulkan device
2026-10-13 13:45:23 +02:00
AlxcBTW 230b5c2683 perf(agc-driver): join the imports of adjacent large ranges when a buffer is bound across them
8 MiB window, so a range larger than the window is always imported alone. A
buffer bound across two such ranges then has no import and is copied whole on
every use: PPSA25344 binds a 368 MiB buffer across a 320.75 MiB and a 47.3 MiB
range and copies it on almost every frame.

When UploadFinish meets such a region, it imports the run of the ranges the
region crosses, provided every one of them is larger than the window, and
retires their own imports. It does this before any region of the build
confirms an import, so the retire moves the epoch ahead of every pointer the
build would use. A range that large is registered whole, not grown in 64 KiB
pieces like a heap, so the joined import is not re-imported as a heap grows; it
stands in refreshImports while exactly its ranges stand. A later join that
reaches a joined import takes it in, so two joins that share a range never
retire each other in turn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:45:21 +02:00
Adrià Franch 1137c57572 ci(windows): build only the execution tests that run without a Vulkan device
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 13:44:08 +02:00
Adrià 99e4dfefe7
Merge pull request #5100 from adriadam10/ci/dispatch-gate-matrices
ci(build): run relinker and context matrices on dispatch only when touched
2026-10-13 13:42:58 +02:00
Niko 44767a7b97 perf(libc): size each write-watch query to the region it covers
WindowsMappings::Collect handed GetWriteWatch the whole remaining output
capacity for every private region it walked. The call's cost follows that
capacity, not the size of the range: on Windows 11 (26200) a query of one
16 KiB region took 0.35 us with room for 4 entries and 6.5 us with room
for the 65536 the write tracker passes. Flexible memory is committed in
16 KiB allocations, one region each, so a resetting walk over 33 MiB of it
took 14.7 ms, 5.8 times a memcmp of the same bytes.

Each query now gets room for the pages its region spans, which is the most
it can report, so every walk returns the same pages; the 33 MiB walk takes
1.23 ms. guest_memory checks that a walk over eight 16 KiB allocations
reports every stored page once, in order, with room for 32, 5 and 1 pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:40:33 +02:00
Adrià 2f969f147b
Merge pull request #3973 from MarcZX100/codex/carry-rudp-end-terminate
fix(libSceRudp): correct End and Terminate functions
2026-10-13 13:40:04 +02:00
Adrià e57a793958
Merge pull request #3911 from GalaxyGamingFR/fix/pr-overlap-own-branch
fix(tools): drop the branch's own pull request in pr_overlap --branch
2026-10-13 13:39:14 +02:00
Adrià Franch 3c273e7081 ci(build): run relinker and context matrices on dispatch only when touched
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 13:39:04 +02:00
Dean 9fa50827dd
Merge pull request #4532 from DavidSamir/fix/libc-rename-replace-open-destination-windows
fix(libc): replace an open or read-only destination in rename on Windows
2026-10-14 00:38:14 +13:00
Evgeniy Kazarin e3cef332e6 feat(libc): implement generic error category messages 2026-10-13 14:38:04 +03:00
Feuris cd0e9dccd7 feat(libc): implement wcscat 2026-10-13 08:38:02 -03:00
Dean 18414447b9
Merge pull request #4525 from Lorkydey/fix/poll-priority-windows
fix(libkernel): support POLLPRI on Windows sockets
2026-10-14 00:37:59 +13:00
boykopovar 36ea209e72 fix(wasm): enable windows diagnostics and disable gui mode 2026-10-13 14:37:50 +03:00
Dean e09ee165d5
Merge pull request #3651 from MarcZX100/codex/libc-posix-spawn-3624
feat(libSceLibcInternal): implement posix_spawn actions
2026-10-14 00:37:44 +13:00
Dean bc1ded3a18
Merge pull request #4386 from MarcZX100/codex/carry-mlockall-getdtablesize-3628
feat(libkernel): add mlockall export
2026-10-14 00:37:29 +13:00
XairRrR 95f34a0504 fix(agc): report GPU time per presented or dropped frame
The [present] line divided the GPU busy and idle time of a window by the
presentations that got a swapchain image. That time covers the GPU work
of every frame, so with frames dropped for want of an image it read
several times too high (278.9 ms instead of about 52 ms on a hidden
window, reported on #4684). Those two figures are now divided by the
presented and dropped frames; the per-present blit figures are unchanged.
2026-10-13 13:34:19 +02:00
bubblegg 4b7a357bd2 fix(savedata): report a save's size as the mount that created it gave
Every native save reported SAVE_DATA_BLOCKS_MAX blocks, all of them free,
in the sceSaveDataDirNameSearch infos and in sceSaveDataGetMountInfo,
whatever the title created it with and whatever its files held. A save's
size is now the blocks of the sceSaveDataMount3 call that created it,
kept beside the save; a save without a kept size takes that of its next
mount that names one, and otherwise keeps SAVE_DATA_BLOCKS_MAX. Free
blocks are what the save's files leave of it, each file rounded up to
32 KiB blocks, and the blocks and free-blocks sort keys use both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:32:43 +00:00
boykopovar 33432725d6 fix(web): limit executable detection to app root 2026-10-13 14:30:57 +03:00
XairRrR 37d9ef133f fix(agc): drop a presentation instead of waiting for a swapchain image
The presenter acquired the next swapchain image with a 5 s timeout
before completing the guest's flip. With FIFO on Wayland, NVIDIA's
driver hands out about one image per second while the window is hidden
(another workspace or occluded): vkAcquireNextImageKHR blocked for
~1 s per flip, and the title ran at exactly 1 frame per second. Stack
snapshots of Uncharted: Legacy of Thieves Collection (PPSA05684) showed
the presenter in drmSyncobjTimelineWait under AcquireImage in every
snapshot taken during such a stall, and in none outside them.

The acquire no longer waits: VK_NOT_READY or VK_TIMEOUT drops that
presentation, as an out-of-date swapchain already does, and the flip
completes. APS5_PROFILE_DRAW's [present] line counts the drops.

Menu with the window moved to an empty workspace for 50 s: 7.5 fps and
about 65 drops per 10 s while hidden (1 fps before), no drops while
visible.
2026-10-13 13:30:47 +02:00
Adrià e99a1b0aa9
Merge pull request #3903 from GalaxyGamingFR/fix/conventions-body-bom
fix(conventions): read the PR body file with utf-8-sig
2026-10-13 13:30:34 +02:00
Adrià f56d638a5a
Merge pull request #3688 from CouchRiv/fix-libc-acosf-errno
fix(libc): keep the acosf result and leave errno unchanged
2026-10-13 13:29:58 +02:00
p3nicillin aebc3f1480 feat(libc): export tzname
ES-DE in RetroArch (PPSA99169) imports tzname from libSceLibcInternal and
fails to load without it; ICU's uprv_tzname reads it after localtime. It
points at the host's zone names and tzset refreshes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:28:33 +01:00
boykopovar a227719658 fix(web): detect guest modules by elf signature 2026-10-13 14:27:07 +03:00
boykopovar 1d99664fb9 feat(web): support folder input 2026-10-13 14:24:33 +03:00
boykopovar 5e762427b4 style(web): simplify converter heading and notes 2026-10-13 14:18:40 +03:00
Dean 5d50886ee4
Merge pull request #2076 from jdmagic/feat/agc-stencil-plane-storage
feat(libSceAgcDriver): take a one-layer 2D array view of a depth surface plane as the plane
2026-10-14 00:11:01 +13:00
Dean 3ee394ea9a
Merge pull request #4543 from coltken95/fix/libc-time
fix(libc): format strftime and asctime as FreeBSD 11 does
2026-10-14 00:10:43 +13:00
Dean 6f7cda184b
Merge pull request #4315 from JAB-dev/feat/agc-dcc-packed-float-clear
feat(agc): encode packed R11G11B10 float DCC fast clears
2026-10-14 00:10:16 +13:00
Dean 50578eb936
Merge pull request #4216 from Mouad-Scriptz-0/perf/guest-memory-registry-lookups
perf(libkernel): find guest allocations and direct mappings by address
2026-10-14 00:09:54 +13:00
Dean 0745fdd72f
Merge pull request #4872 from David-cmrg/fix/systemservice-loadexec-exit-order
fix(libSceSystemService): run guest exit handlers first on LoadExec exit
2026-10-14 00:09:38 +13:00
boykopovar 9144f7ac2c feat(web): add browser converter interface 2026-10-13 14:05:33 +03:00
boykopovar 57801875db refactor(web): load zip.js from pinned cdn version 2026-10-13 14:02:46 +03:00
Adrià c8eb1f52d3
Merge pull request #3898 from GalaxyGamingFR/fix/progress-wrapper-definitions
fix(progress): recognise non-static and noexcept stub helpers
2026-10-13 13:01:36 +02:00
lorkydey d4b59ce9fa fix(agc): accept inactive vertex point size on non-point draws 2026-10-13 12:56:44 +02:00
Kovalev Vladislav 319fa5779a feat(relinker): support fixed Windows guest image bases 2026-10-13 12:55:54 +02:00
Adrià b1328fc0f9
Merge pull request #4100 from nyavana/docs/relinker-help-refresh
docs(relinker): correct help and exit-code usage
2026-10-13 12:54:27 +02:00
hugodearaujo 5c6a9d22c4 fix(libkernel): check and keep the scheduling policy of a thread
On a PS5 (firmware 13.60) pthread_setschedparam and
scePthreadSetschedparam accept only SCHED_FIFO and SCHED_RR with a
priority of 256 to 767 or 896 to 959, return EINVAL otherwise, and
keep the policy for pthread_getschedparam. A created thread takes the
policy of explicit scheduling attributes, or its creator's when it
inherits. Here any policy and priority were accepted and SCHED_FIFO
was always reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:53:19 +02:00
Adrià Franch e34281b558 docs(debt): keep the other SSL stubs in the PPSA07411 entry
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 12:50:47 +02:00
MarcZX100 5d00bd7bbf feat(libSceSsl): add missing verification callback export 2026-10-13 12:50:43 +02:00
Yaash Singhh 4f87ac0b1c fix(libkernel): harden DirectMemory pool bounds and rollback 2026-10-13 10:49:27 +00:00
boykopovar 78df1e3244 feat(web): stream zip conversion and release library packaging 2026-10-13 13:48:23 +03:00
Dean 075169f7b3
Merge pull request #4404 from eljackjoestar-cmd/codex/demanded-shader-preparation
fix(agc): prioritize demanded shader preparation
2026-10-13 23:42:40 +13:00
Dean 768cd93977
Merge pull request #4082 from Celegans12/feat/agc-quad-tessellation
feat(agc): implement quad tessellation with counter-clockwise output and level clamps
2026-10-13 23:42:25 +13:00
Dean 1d7b075610
Merge pull request #4496 from Kikoarl/perf/agc-gds-dma-and-completion-label-sync
perf(agc): disambiguate completion label overlaps in CopyBuffer
2026-10-13 23:42:11 +13:00
boykopovar 34766c8236 feat(relinker): expose wasm conversion bindings 2026-10-13 13:38:47 +03:00
Adrià Franch 3949fb9d44 test(agc): skip copied-direct ordering without Vulkan and find libc on Windows
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 12:34:08 +02:00
TibixDev 29b227bf35 fix(agc): complete copied writes before direct consumers
Wait for overlapping CPU writebacks and completion labels before importing buffers or accepting cached image resources. Cover texture data and compression metadata, retain asynchronous disjoint and GPU-only dependencies, and avoid recursive completion waits.

Reproduced fresh-buffer and cached-image failures with CPU Vulkan before fixing them. Regression covers fresh/reused bindings, dispatch/draw copied writers, texel/metadata updates, labels and no-wait cases; passes CPU Vulkan and RX 6600 synchronization validation. Graphics and guest-memory suites pass. The Skyrim loading GPU fault remains unattributed.

AI-assisted implementation and independent code review.
2026-10-13 12:34:03 +02:00
Dean 53aea1ff34
Merge pull request #5024 from oneandonlydean/up4/storage-store-keeps-untracked-writes
fix(agc): keep CPU writes when a pending storage result is stored over untracked memory
2026-10-13 23:33:08 +13:00
Dean 387b8a0faa
Merge pull request #3763 from eljackjoestar-cmd/codex/dynamic-rendering-layers
fix(agc): render all attachment layers with dynamic rendering
2026-10-13 23:32:53 +13:00
Adrià Franch 99ebc650c3 fix(agc): zero dword fill only for 32-bit output formats
The kernel stores through the V# FORMAT; with an 8- or 16-bit format it writes 1 or 2 bytes per element, which a zero fill of the whole range would also clear between. Same check as MatchDwordPatternFill (format 20-22), with test rows.
2026-10-13 12:29:00 +02:00
jagrat Singh 9efabff1cb feat(libkernel): return ESRCH and EINVAL for unsupported cpuset affinity targets
Allow calling threads to query and set affinity using their own thread ID in addition to -1. Return ESRCH for non-matching thread or process IDs and EINVAL for invalid level/which arguments instead of throwing NotImplemented, matching FreeBSD cpuset semantics.
2026-10-13 15:58:11 +05:30
Daan Dehing 501453573c perf(agc): handle the zero dword fill kernel as a buffer fill
A wave64 compute kernel that stores dword 0 at index group * 64 + thread through a 4-byte
stride buffer is run as a buffer fill. Palworld (PPSA23126) clears its DCC keys with it every
frame; as a shader dispatch its writes were unknown to the DCC key proofs, so every refresh of
those targets waited for the GPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:27:46 +02:00
Adrià c7632f036f
Merge pull request #5037 from Feuris/feat/libc-cnd-timedwait
feat(libc): implement _Cnd_timedwait
2026-10-13 12:26:09 +02:00
Adrià a1c2f9fa2c
Merge pull request #3902 from MarcZX100/codex/carry-amm-pool-references-3321
fix(ampr): preserve pooled pages across AMM remaps
2026-10-13 12:25:36 +02:00
Adrià ae244d527a
Merge pull request #5051 from ducloc080202/feat/system-service-challenge-activity
feat(libSceSystemService): no-op sceSystemServiceOpenChallengeActivity
2026-10-13 12:23:15 +02:00
boykopovar 3b5c35af9e
Merge pull request #5044 from boykopovar/refactor/relinker-core-di-iprogress
refactor(relinker): relinker core di
2026-10-13 13:23:12 +03:00
Dean Galvin cc3b47dda0 fix(libSceAgcDriver): take a one-layer 2D array plane view as a narrow exception to the non-2D refusal
Main refuses every storage view of a depth or stencil plane that is not
2D. A 2D array view is now taken as the plane only at layer 0 with one
layer; a view with more layers or another base layer still throws.

A one-layer 2D array view replaces a 2D view of the plane like any other
view, so a store back through the replaced 2D view throws. The depth
storage dispatch test runs one-layer views of both planes and checks
that the depth and stencil tests see what they stored, and that a
two-layer view still throws.
2026-10-13 23:17:51 +13:00
jdmagic e4a7cbfc83 feat(libSceAgcDriver): take a one-layer 2D array view of a depth surface plane as the plane
A storage view of a depth or stencil plane was taken for the depth surface
only as a 2D image. A 2D array view of layer 0 with one layer and the
plane's extent and format is the same plane, and now gets the plane's
storage image too; a view with more layers still takes the ordinary path.
The plane's storage image is recreated when the view's dimension changes.

PPSA01289 (Sackboy: A Big Adventure) binds the stencil plane of its
2880x1620 D32S8 surface as a one-layer R8_UINT 2D array from a compute
shader during presentation, and read guest memory instead of the stencil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 23:15:15 +13:00
Karan Vora e4f212b2e2 perf(shader): convert f16 operands with UnpackHalf2x16 where f16 denormals are kept
Since #1463, every f16 operand read decodes sign, exponent and mantissa
with integer operations, 8 to 12 instructions more per read than
UnpackHalf2x16 on NVIDIA. The decode works around an AMD Windows driver
that folds the mask of a byte-selected half into UnpackHalf2x16.

A new target flag, float16DenormPreserve, is set when the device reports
shaderDenormPreserveFloat16 and denormBehaviorIndependence ALL, the same
rule as float64DenormPreserve. With it, EmitF16BitsToF32 uses
UnpackHalf2x16 and declares DenormPreserve for 16-bit floats, under
which SPV_KHR_float_controls keeps unpacked subnormal halves. NVIDIA
returns the default NaN for every NaN half, so the NaN bits are rebuilt
from the half: its sign at bit 31, its payload at bits 22:13. The
DenormPreserve 16 mode is declared once, shared with the native f32 to
f16 conversion. Without the flag (lavapipe; RADV reports 32_BIT_ONLY)
the integer decode stays. Halves of fields narrower than 16 bits, such
as SDWA byte selects, keep the integer decode on every device.

The flag is serialized (request version 17) and part of the cache key.

New test agc_driver_f16_to_f32_unpack converts all 65,536 halves, with
nonzero high bits, through v_cvt_f32_f16, and byte-selected halves
through v_add_f16 SDWA, with each decode the device supports, and
compares the bits with an exact decode. agc_driver_f16_to_f32_unpack_spirv
checks which decode the SPIR-V uses with and without the flag.
2026-10-13 12:15:00 +02:00
JAB-dev a96f8bd640 feat(agc): encode packed R11G11B10 float DCC fast clears
A fast clear of a packed float color target (format 36) was refused as unencodable. Give the format
a DCC layout (11, 11 and 10 bit float channels) and its one value, so 0000, 0001, 1110 and 1111
clear codes fill the texels and a texture keeps those keys.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 23:14:10 +13:00
Claude d0df62bd1f
fix(libc): format strftime and asctime as FreeBSD 11 does
strftime handed most conversions to the host's strftime, which differs
from FreeBSD 11's for E and O modifiers on conversions glibc does not
pair with them (%Ea was printed literally), padding flags on %+ and %v,
years outside 1000 to 9999 (%Y printed 899 and -1 where FreeBSD prints
0899 and -001), and out-of-range fields (%I of hour 100, %u of weekday
8). On Windows the padding flags printed nothing. strftime now follows
FreeBSD 11 strftime.c with the C locale on every host, and asctime
follows FreeBSD 11 asctime.c, padding years to four digits and setting
longer years apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-13 10:12:15 +00:00
Mouad-Scriptz-0 df3d027ebe perf(libkernel): find guest allocations and direct mappings by address
sceKernelVirtualQuery, sceKernelMunmap, sceKernelReleaseDirectMemory and the
reservation paths walked a copy of the whole allocation registry or of every
direct mapping under one lock on each call. The registry now answers lookups
from its ordered map, applies range replacements as patches instead of
rebuilding the map, and direct mappings carry an index by physical offset so a
release finds only the mappings it covers. Minecraft (PPSA17221) holds about
7,000 direct mappings and spent its world generation in these walks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 23:11:32 +13:00
Adrià Franch ff6c1ea5f3 fix(stubgen): reconfigure stdout only when it supports it
Callers that replace sys.stdout (test_stubgen redirect_stdout) have no reconfigure().

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 12:07:13 +02:00
GalaxyGamingFR f6d5404f45 fix(stubgen): write LF to stdout on Windows
When --out was not given, stubgen wrote the generated code and debt lines to
sys.stdout, which translates LF to CRLF on Windows, so redirecting stdout
produced CRLF files. stdout is now reconfigured to utf-8 with LF newlines,
matching the --out path. A subprocess test checks the bytes on stdout.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 12:06:59 +02:00
David-cmrg 9f9c351f54 fix(libSceSystemService): run guest exit handlers first on LoadExec exit 2026-10-13 12:03:05 +02:00
boykopovar 04899cb0f7 fix(relinker): align console progress columns 2026-10-13 13:02:03 +03:00
GalaxyGamingFR 0817454371 fix(tools): drop the branch's own pull request in pr_overlap --branch
The --branch mode removed the branch's own open pull request only when its
head equalled the local branch exactly. Checking commits before pushing
left the branch ahead of its pull request, so the tool reported the user's
own pull request as overlapping. The filter is now a function that also
drops any pull request whose head is an ancestor of the branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 12:00:41 +02:00
boykopovar a534bd67ca fix(relinker): report intermediate output image progress 2026-10-13 12:59:23 +03:00
boykopovar d35b1afa51 fix(relinker): use consistent two-space nesting in runtime layout 2026-10-13 12:59:22 +03:00
boykopovar c9a94dd021 fix(relinker): remove layout padding and blank lines after headings 2026-10-13 12:59:04 +03:00
boykopovar 754b82163b fix(relinker): remove indentation from conversion summary 2026-10-13 12:58:48 +03:00
boykopovar 868d7a138d fix(relinker): separate console sections without spacing every message 2026-10-13 12:58:35 +03:00
boykopovar 6f2e4b6902 test(relinker): update runtime layout expectations for tree output 2026-10-13 12:58:35 +03:00
boykopovar 56c2a53188 fix(relinker): redraw console progress and format runtime layout as a tree 2026-10-13 12:58:34 +03:00
boykopovar e1ef33047c fix(relinker): validate scan ranges before narrowing memory offsets 2026-10-13 12:57:55 +03:00
boykopovar 3e658db4b6 refactor(relinker): remove the obsolete file-based icon builder 2026-10-13 12:57:55 +03:00
boykopovar 6224febfb0 feat(relinker): report instruction conversion progress for executables and modules 2026-10-13 12:57:54 +03:00
boykopovar b42aa8c540 feat(relinker): expose in-memory conversion through a portable core library 2026-10-13 12:57:53 +03:00
boykopovar 5e5eba8922 fix(relinker): reject layouts that would discard exception metadata 2026-10-13 12:57:06 +03:00
boykopovar 37e25a2a78 refactor(relinker): separate native module discovery from prx conversion 2026-10-13 12:57:05 +03:00
boykopovar 02cd2e57e2 refactor(relinker): move windows icon and diagnostic io to native adapters 2026-10-13 12:56:42 +03:00
MarcZX100 81f727c051 test(libc): match syslog PID formatting 2026-10-13 09:56:31 +00:00
MarcZX100 7313cf5589 docs(libc): record syslog tag fallback gap 2026-10-13 09:56:31 +00:00
MarcZX100 653c5449f9 fix(libc): honor openlog identity and facility 2026-10-13 09:56:31 +00:00
boykopovar cd0433fd82 feat(relinker): report syscall scanning and import analysis progress 2026-10-13 12:56:16 +03:00
boykopovar 04ca1721e5 feat(relinker): add progress interface and console reporter 2026-10-13 12:55:34 +03:00
Adrià 77b9f7270c
Merge pull request #3579 from Celegans12/fix/relinker-present-optional-provider-errors
fix(relinker): preserve load failures of present optional providers
2026-10-13 11:53:01 +02:00
Alex 988d304c5c fix(libc): keep the acosf result and leave errno unchanged
The previous commit replaced the out-of-range result with the default
quiet NaN 0x7fc00000, but main and FreeBSD e_acosf.c return 0xffc00000.

acosf now calls the host and restores errno, so only errno differs from
main. The guest test pins the result bits for 2.0f and -2.0f and keeps
the in-range case acosf(0.5f).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 11:49:14 +02:00
Alex 64e244eb70 fix(libc): match FreeBSD acosf errno
acosf returned 0xffc00000 (errno 33) for 2.0 (0x40000000), where FreeBSD
lib/msun/src/math.h returns 0xffc00000 (errno 0).

It now returns the FreeBSD result for that case. A guest test covers it
and fails on main.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-13 11:49:14 +02:00
Adrià 8bcd97cd5b
Merge pull request #1418 from gjonn/feat/agc-unnormalized-implicit-lod
feat(agc): sample the base level through unnormalized samplers
2026-10-13 11:49:07 +02:00
GalaxyGamingFR d15cc41299 fix(conventions): read the PR body file with utf-8-sig
A pull request body saved with a UTF-8 byte order mark starts with
U+FEFF before "### What", so the first heading is not recognised and the
checker reports the What section as missing. Decode the body file with
utf-8-sig so the mark is dropped and the sections are found.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 11:48:36 +02:00
GalaxyGamingFR 02dad4429f fix(progress): recognise non-static and noexcept stub helpers
The stub helper pattern required a leading static and a plain signature,
so exports calling helpers in anonymous namespaces, or helpers with
noexcept, a trailing return type or a pointer next to the name, counted
as done. The pattern now anchors at line start, makes static optional,
skips APS5_VABI exports and control keywords, and accepts those suffixes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-13 11:42:32 +02:00
ducloc080202 4aff906ca6 feat(libSceSystemService): no-op sceSystemServiceOpenChallengeActivity 2026-10-13 16:41:40 +07:00
Dean bb9a4d8a24
Merge pull request #5045 from oneandonlydean/up4/fix-clip-cull-draw-skip
test(agc): skip the clip and cull distance draw without a Vulkan device
2026-10-13 22:38:00 +13:00
Dean 2890f95494
Merge pull request #5025 from 0xRickx/fix/libkernel-sys-rename-import
fix(libkernel_sys): reach rename through a _nid_no_patch export
2026-10-13 22:37:36 +13:00
Adrià 08f672cc51
Merge pull request #5035 from ducloc080202/feat/system-service-controller-settings
feat(libSceSystemService): no-op sceSystemServiceShowControllerSettings
2026-10-13 11:35:54 +02:00
Feuris 572d330a13 feat(libc): implement _Cnd_timedwait 2026-10-13 06:34:01 -03:00
Dean Galvin 4a4bea9d1b test(agc): skip the clip and cull distance draw without a Vulkan device 2026-10-13 22:26:59 +13:00
xXPBSXx 51c7206fd0 fix(libScePlayGo): answer chunk ids from the package layout
A package with no playgo-* file in sce_sys has no PlayGo data, so only chunk 0
is valid and any other id returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. A package with
playgo-scenario.json but no chunk table (PPSA01748) keeps accepting every id.
A chunk table (playgo-chunk.dat or playgo-chunkdefs.xml) still decides when it
exists. A sce_sys that holds other playgo-* files without a chunk table or a
scenario file, or a playgo-chunk.dat that is not a plgx table with a nonzero
count, throws naming the file, since no such dump is known.

Without this a title that walks the ids until the first error (Sifu PPSA03001)
never gets the error.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 11:26:43 +02:00
Adrià 8299b2f7eb
Merge pull request #5036 from 0xRickx/feat/libc-atanhf
feat(libc): implement atanhf
2026-10-13 11:22:59 +02:00
Rujul Talekar 290675799e test(tools): drop the Ninja-on-PATH requirement from the registration suite
Remove test_built_uses_configured_ninja_outside_path per review: it copied
whatever ninja was on PATH and asserted one existed, so the suite failed on
exactly the setup this PR fixes. The rewritten tests already verify the
configured CMAKE_MAKE_PROGRAM is the program that runs; the suite now passes
with and without Ninja on PATH on Windows and Linux.
2026-10-13 14:51:04 +05:30
Ondra97 bde680c855 fix(relinker): map standalone RELRO in unused import filtering 2026-10-13 11:19:36 +02:00
screamm 5db1d8d5e9 fix(libkernel): accept POLLPRI on guest sockets under WSAPoll
Three catalog titles stop on Windows when they poll a guest socket for
POLLPRI|POLLOUT to see whether a non-blocking connect has completed:

- PPSA97510 PSXS5 (socket 0x10000002, thread gamedb, 13 s):
  what():  poll: POLLPRI is not supported by WSAPoll
- PPSA98510 SwanStation (sockets 0x10000003/0x10000002, threads gamedb
  and update): what():  poll: POLLPRI is not supported by WSAPoll
- PPSA99003 ProsperoTV ({0x10000001, POLLPRI|POLLOUT} at 5.3 s):
  what():  poll: POLLPRI is not supported by WSAPoll

FreeBSD's sopoll_generic (sys/kern/uipc_socket.c, freebsd-src 8c639945)
reports POLLPRI and POLLRDBAND alike, only while out-of-band data is
pending (so_oobmark or SBS_RCVATMARK). WSAPoll rejects POLLPRI in events
with WSAEINVAL but reports pending urgent data as POLLRDBAND, so on
Windows the guest POLLPRI is now asked of WSAPoll as POLLRDBAND and
POLLIN as POLLRDNORM (Winsock's POLLIN includes POLLRDBAND, which would
report urgent data as readable). Measured on this host: WSAPoll reports
POLLRDBAND after a peer's send(MSG_OOB), waits for it, and clears it once
the byte is read with MSG_OOB. Linux keeps polling POLLPRI on the host.

select needs no change: libkernel's select passes exceptfds as Urgent to
the libSceNet poller, which already asks WSAPoll for POLLRDBAND, and it
does not take libkernel guest sockets on either host.

The guest send and recv refuse MSG_OOB, so urgent data only comes from a
peer outside the guest's sockets; guest_poll now sends it from a host
socket and checks that a connected pair and a non-blocking connect
report POLLOUT and not POLLPRI. TechnicalDebt records where Winsock's
answer differs from FreeBSD's once the stream passes the mark.

Depends on #3649 (poll on file descriptors), whose two commits this
branch carries, since the titles reach this stop only with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 11:15:48 +02:00
Sanjaysrinivas 0612c181ff fix(agc): avoid storage snapshot overlap
Create uploads before publishing snapshot validity. Keep allocation
edits separate from the per-unit validity changes in #5024.
2026-10-13 11:11:58 +02:00
eljackjoestar-cmd dedb869fa2 test(agc): shut down the layered submission driver before exit 2026-10-13 13:07:18 +04:00
ducloc080202 46c7766f4f feat(libSceSystemService): no-op sceSystemServiceShowControllerSettings 2026-10-13 16:05:00 +07:00
eljackjoestar-cmd 2ae227ef85 fix(agc): integrate merged position exports and request version 21 2026-10-13 13:03:12 +04:00
eljackjoestar-cmd 78ad5d9dfb fix(agc): validate dynamic layer limits and host subgroup size 2026-10-13 13:01:17 +04:00
Dean 2a2a3dc650
Merge pull request #4226 from MarcZX100/codex/carry-wcsftime-3625
feat(libc): implement wcsftime
2026-10-13 22:01:10 +13:00
Dean 90285be0af
Merge pull request #4367 from MarcZX100/codex/carry-windows-alias-4260
fix(libc): alias non-contiguous shared guest views on Windows
2026-10-13 22:00:55 +13:00
eljackjoestar-cmd 13c4a2a6c6 fix(agc): preserve main interfaces in the layered rendering rebase 2026-10-13 13:00:51 +04:00
Dean 48c48ffd9e
Merge pull request #4390 from ErenYeager1836/fix/pngdec-validate-size-and-max-width
fix(libScePngDec): validate this_size on create
2026-10-13 22:00:41 +13:00
eljackjoestar-cmd a103e48c8b test(agc): use the current fragment push slot in layered readback 2026-10-13 13:00:28 +04:00
eljackjoestar-cmd 93a090ed8d test(agc): retain array-view checks after merge 2026-10-13 13:00:28 +04:00
eljackjoestar-cmd 60a1649e76 fix(agc): render all attachment layers with dynamic rendering 2026-10-13 13:00:28 +04:00
alfalfa-star 0d61dad293 docs(agc): record the DCC key extent assumed for 3D color targets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:00:28 +04:00
alfalfa-star 425a4daf16 fix(agc): report layer exports as ignored only when a draw does not route them
The warning fired for every draw with PA_CL_VS_OUT_CNTL layer bits,
including layered draws that now route the render target index. It is
checked after the color targets are decoded and leaves out the routed
bits and the misc vector enable. The comment that said layer exports
are never routed is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:00:28 +04:00
Dean 501f4f5aa7
Merge pull request #4835 from MarcZX100/fix/agc-init-version-error-4808
fix(agc): return error for unsupported init versions
2026-10-13 22:00:27 +13:00
Dean 02d4839b60
Merge pull request #4584 from xXPBSXx/fix/agc-line-strip-primitive
fix(agc): decode primitive type 3 as a line strip
2026-10-13 22:00:05 +13:00
alfalfa-star dd70286889 test(agc): draw a layered volume through the driver
agc_driver_layered_volume_submit submits a DCB whose context registers
alone describe a 3D render target (CB_COLOR_ATTRIB3 resource type 3D,
CB_COLOR_VIEW slices 1-3) and set PA_CL_VS_OUT_CNTL USE_VTX_RENDER_
TARGET_INDX, with both shaders registered before the draw. It checks
that each band lands in its own slice. Removing the layer export from
the vertex stage info in Driver::draw, or the bit-18 read in
DecodeState, fails it. Two more runs draw the volume under DCC keys:
uncompressed keys stay uncompressed, and 0000 fast-clear keys leave
every texel the draw does not write at the clear color and end
uncompressed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:00:04 +04:00
alfalfa-star 97d192eeae test(agc): pass the GPU flag to Mutation::Add in the layered volume test
Main added the GPU-visible argument to GuestAllocations::Mutation::Add.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:00:04 +04:00
alfalfa-star 1055617751 feat(agc): render layered draws into 3D color targets
A color view of several depth slices of a 3D target (CB_COLOR_VIEW
SLICE_START < SLICE_MAX) was rejected as "color views of several array
slices are unsupported". Titles render such volumes with one draw: an
instanced draw whose vertex stage picks each primitive's slice through
the misc position export (PA_CL_VS_OUT_CNTL USE_VTX_RENDER_TARGET_INDX
with VS_OUT_MISC_VEC_ENA).

Depends on #423, which carries PA_CL_VS_OUT_CNTL to the recompiler.

- DecodeColorBuffer takes the slice range of a 3D target
  (ColorTarget::layers, clamped to the surface's last slice), allows DCC
  on 3D targets, and sizes a tiled 3D target by its whole surface
  (SurfaceForTarget moves to State.cpp for that). DecodeState sets
  State::renderLayers and, for a layered draw, USE_VTX_RENDER_TARGET_INDX
  (State::layerExports); color targets of different slice counts and
  layered draws with a depth target throw.
- The driver adds State::layerExports to the PA_CL_VS_OUT_CNTL bits #423
  passes (it already passes VS_OUT_MISC_VEC_ENA), so the render target
  index reaches gl_Layer only for layered draws and stays ignored
  elsewhere as before.
- A vertex stage writing gl_Layer declares ShaderViewportIndexLayerEXT
  and SPV_EXT_shader_viewport_index_layer when the device offers them
  (the device enables VK_EXT_shader_viewport_index_layer when present),
  instead of SPIR-V 1.5 ShaderLayer, which a Vulkan 1.1 device cannot
  take. Graphics validation accepts the capability, the extension and a
  vertex Layer output when it is enabled, and a per-primitive Layer
  output of a mesh stage.
- The resident target's attachment view is a 2D array view of the
  slices, and the framebuffer has that many layers (Framebuffer and
  AcquireFramebuffer take the layer count).

The execution test agc_driver_layered_volume_draw draws three bands,
one per layer, into slices 1..3 of a 4-slice 64 KiB-tiled volume and
reads every slice back: slice 0 stays untouched and slice 1 + L holds
only band L. It also recompiles a mesh program with the layer export and
validates it against the layered state. The mesh case does not draw:
lavapipe's LLVM backend aborts compiling that mesh pipeline ("Cannot
emit physreg copy instruction"), which a test cannot catch. On RADV the
same mesh draw renders the bands into the right slices.

PPSA14632 (LEGO Horizon Adventures) renders its 64x64x64 RGBA16F
translucency lighting volumes (two DCC targets, 64 instances) this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:00:04 +04:00
Sanjaysrinivas 3f314030b4 fix(agc): use storage factory in snapshot test 2026-10-13 10:59:20 +02:00
Sanjaysrinivas a296b9cacf fix(agc): register snapshot fixture GPU memory 2026-10-13 10:59:20 +02:00
Sanjaysrinivas 65eb466ddd fix(agc): avoid snapshot upload PR conflict 2026-10-13 10:59:20 +02:00
Sanjaysrinivas e2ee9430bf perf(agc): allocate CPU snapshots on demand 2026-10-13 10:59:20 +02:00
Celegans12 23342340cc feat(agc): implement quad tessellation with counter-clockwise output and level clamps
DecodeShaderStages accepted only clockwise triangle patches and no HOS
level clamp narrower than [1, 63], so terrain drawn as TRI_CCW quad
patches with VGT_HOS_MAX_TESS_LEVEL 9 aborted. Quad domains and TRI_CCW
now decode and emit Quads and VertexOrderCcw; isolines, other
partitionings and point or line output still throw.

VGT_HOS_MIN/MAX_TESS_LEVEL are read per draw and pushed in the last 8
bytes of the pre-rasterization push constant slot, where the hull reads
them to clamp its factors; they stay out of every key and the recompile
request, so one hull serves every level. Zero, negative and NaN outer
factors still cull; clamps outside 0 <= min <= 63, max >= 1,
min <= max throw. Quad hulls write four outer and two inner factors at
a 24-byte stride, the layout Mesa's TF ring store uses.
2026-10-13 10:56:16 +02:00
Rick 9ceb6d144d fix(libkernel_sys): reach rename through a _nid_no_patch export
renameat (2a8e7452) calls rename_nid_postfix when both paths are
AT_FDCWD-relative or absolute. Rename.cpp is built into both libc and
libkernel, and on Windows libkernel_sys bound that import to libkernel,
which comes first on its link line. The NID patcher then rewrote the
import to rename's NID, which only libc exports, as libkernel keeps its
copy under the plain name. So libkernel_sys.prx fails to load with error
127 on Windows, and with it every title that imports it. Linux resolves
the symbol globally and was not affected.

rename's body is now RenameGuestPath_nid_no_patch, which both libraries
export under that name, and renameat calls it, the way libkernel_sys
already reaches libkernel's other helpers. rename_nid_postfix forwards
to it, so its behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 10:48:14 +02:00
Rick 3fe04d4b72 feat(libc): implement atanhf
Dusklight (PPSA99305) imports atanhf (cPGyc5FGjy0) from
libSceLibcInternal.prx; the libc.prx it bundles only has a zero-return
stub for it.

The implementation follows the atanhf of the libc.prx bundled with
PPSA28319 (0x438a0), read from its disassembly: FreeBSD msun's
e_atanhf.c calling msun's s_log1pf.c, both as of 59bc2f09 (stable/9,
the revision the sinhf port took expm1f and expf from). The log1pf
paths for the positive arguments atanhf passes are inlined, as the
exported log1pf is still the host's. For |x| > 1, the infinities and
NaN, Sony's error helper raises FE_INVALID and sets errno to EDOM
before returning (x - x) / (x - x); for |x| = 1 it sets errno to
ERANGE before returning x / 0. Other arguments leave errno alone.

Running that code from the title's libc.prx on a Windows host gives
the same bits, errno and floating-point exceptions as the built
libc.prx for all 2^32 arguments, and msun's own e_atanhf.c and
s_log1pf.c built with the host compiler give the same bits. With the
host log1pf instead of the msun one, 4.7% of the arguments in [0, 1)
differ. guest_math pins bits for every branch reachable from atanhf,
both signs, and the errno and exception behaviour.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 10:48:06 +02:00
Dean 4bb2c7f394
Merge pull request #423 from MichonGoddijn231849/feat/clip-cull-distances
feat(agc): vertex clip and cull distances
2026-10-13 21:47:43 +13:00
Adrià b87708353c
Merge pull request #5017 from adriadam10/feat/proprietary-voice-chat-helper
feat(libSceProprietaryVoiceChatHelperPrx): implement the voice chat helper lifecycle
2026-10-13 10:47:32 +02:00
Dean Galvin e5449936f4 fix(agc): keep CPU writes when a pending storage result is stored over untracked memory
On memory outside the write watch a write-back compares guest memory with
the bytes saved at the upload and leaves the 64 KiB blocks that differ to
the CPU. A store of some of an image's units marked the whole saved copy
invalid, and a fill turned into an image clear or an image copy never
saved the bytes under it, so the next store had nothing to compare and
wrote its layers whole over what the CPU had written since.

The saved copy is now valid per tracked unit. A store, a drop or a stale
eviction invalidates only its own units, a CPU-path store makes the units
it stored valid again, and the write-back compares each run of selected
units that still has saved bytes. FillClear and CopyFrom save the bytes
of the units they fill when the surface is not watched, as an upload does.

Results over a range that left the watch while they were pending still
have no saved bytes; storing them now throws instead of overwriting the
CPU's writes (technical debt).
2026-10-13 21:46:12 +13:00
Dean d379bfd014
Merge pull request #5022 from oneandonlydean/up4/bda-read-selection-nvidia
fix(shader): load a BDA span in place from its own function
2026-10-13 21:44:21 +13:00
Dean Galvin 8c04efcfbc fix(shader): load a BDA span in place from its own function
read_bda_span chooses between the span's in-place dword loads and its
per-dword byte fallback, which calls read_bda_dword_bytes. Each shape of
that choice so far hangs a group of NVIDIA drivers: a dispatch never
finishes and the device is lost.

As the two arms of one selection, with the loads emitted in the arm,
it hung drivers 591.86 and 590.48.01 when lanes took both arms (#3291).
As two selections, the loads under the span's condition and the fallback
under its negation (#4759), it hangs 595.97, 596.36, 610.62, 610.74 and
610.57.04 (#4975).

The loads now live in load_bda_span, a DontInline function that calls
nothing, and read_bda_span is one selection again: one arm calls
load_bda_span, the other is the fallback as before. Probe, loads,
lookups, faults and stops are unchanged for every lane.

On an RTX 4090 (Linux, driver 610.57.04) the two-selection shape hangs
agc_driver_scalar_wide_loads and agc_driver_flat_apertures_0..13 in a
build with SPIRV-Tools, and agc_driver_bda_span_reads and
agc_driver_pixel_interlock in a build without. All pass with this
change in both builds. Drivers 591.86, 590.48.01, 595.97, 596.36,
610.62 and 610.74 are not tested; a shape with the loads in their own
DontInline function was reported passing on 591.86 in #3291.

agc_shader_memory now requires that a span read function holds no load
and calls its load function once, and that the load function holds the
four loads and no call.

Refs #4975
2026-10-13 21:40:18 +13:00
Michon a72dcb93aa test(agc): clip and cull distances drawn through the device and the driver
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 21:37:49 +13:00
Michon 04138f50ad feat(agc): vertex clip and cull distances
PA_CL_VS_OUT_CNTL's clip and cull enables and its misc and distance vector bits reach the recompiler's vertex info (request version 20), the draw key, the vertex-info comparison and the recompile cache key. Registration and draw-time preparation set them the same way the draw does; a program without pos1..pos3 exports gets none, so its artifact does not depend on the register. Guest clip distances share main's gl_ClipDistance array with the all-zero position distance; cull distances need shaderCullDistance. Up to eight clip and cull distances are accepted.

Co-Authored-By: john.maia <hi@johnmaia.dev>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 21:37:49 +13:00
Matheus Lima da Silva e933285d82 feat(libSceProprietaryVoiceChatHelperPrx): implement the voice chat helper lifecycle
Initialize and Terminate track whether the library is initialized, and
SetVoiceChatState returns success without recording anything: the host has
no system voice chat for a title's own voice chat to announce itself to,
and the state argument is unknown.

GetVoiceChatUsageState keeps throwing. With the state argument unreadable
there is no recorded usage state, and whether the console returns the state
or writes it through an output pointer, and how it encodes it, is unknown.

Misuse throws rather than guessing an error code, as the library's error
codes are unknown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 10:34:39 +02:00
Adrià cac4e9688f
Merge pull request #4960 from fdfawef324/feat/libSceDbgThreadSanitizer
feat(libSceDbgThreadSanitizer): declare the TSan annotation calls and report the sanitizer disabled
2026-10-13 10:34:04 +02:00
Adrià 20890629f2
Merge pull request #4893 from Lorkydey/feat/audioout2-user-supported-attributes
feat(audioout2): report supported user attributes
2026-10-13 10:31:46 +02:00
Adrià cee54cdade
Merge pull request #4918 from Feuris/feat/libc-mtx-init-with-name
feat(libc): implement _Mtx_init_with_name
2026-10-13 10:30:43 +02:00
Santhosh Kumar 44623222c9 fix(agc): exclude skipped vertex records from target alias checks 2026-10-13 14:00:11 +05:30
Adrià 5f426f9478
Merge pull request #4902 from nicolasfalesy/feat/videoout-delete-vrr-status-event
feat(libSceVideoOut): implement sceVideoOutDeleteVrrActiveStatusEvent
2026-10-13 10:29:25 +02:00
Claude 13444c82e9
fix(libc): print NaN without a sign in the guest printf formatter
The guest formatter handed NaN to the host's snprintf, which prints
-nan for a negative NaN and +nan or " nan" with the + and space flags.
FreeBSD 11's vfprintf clears the sign of every NaN and prints nan (NAN
for the upper-case conversions), keeping the width and the - flag and
ignoring 0. The formatter now does the same for a, e, f and g and
their long double forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-13 08:26:41 +00:00
Dean ad653c9bc3
Merge pull request #5015 from oneandonlydean/up4/fix-fmin-zero-sign
fix(libSceLibcInternal): return the negative zero from fminf for zeros of different sign
2026-10-13 21:25:42 +13:00
Dean 637ade873e
Merge pull request #5014 from oneandonlydean/up4/fix-windows-patched-libraries
fix(libc): hand out the unwind cursor table through a _nid_no_patch export
2026-10-13 21:25:34 +13:00
lorkydey 87ee82410b feat(audioout2): report supported user attributes 2026-10-13 10:24:04 +02:00
Adrià e96bfffa59
Merge pull request #4877 from jagrat04/feat/libkernel_sys-renameat
feat(libkernel_sys): implement renameat
2026-10-13 10:23:01 +02:00
jagrat Singh 2a8e745267 feat(libkernel_sys): implement renameat 2026-10-13 10:19:35 +02:00
Adrià 4899658e87
Merge pull request #4882 from Lorkydey/feat/libkernel-coredump-stop-info-cpu
feat(libkernel): answer CPU stop-info queries outside the coredump handler
2026-10-13 10:19:19 +02:00
Adrià db3d379c87
Merge pull request #4870 from jagrat04/feat/libkernel_sys-unlinkat
feat(libkernel_sys): implement unlinkat
2026-10-13 10:16:19 +02:00
Adrià 534451426a
Merge pull request #4860 from jagrat04/feat/libSceNpEntitlementAccess-pft-flag
feat(libSceNpEntitlementAccess): implement sceNpEntitlementAccessGetPftFlag
2026-10-13 10:13:42 +02:00
Dean Galvin cd9573b41c fix(libSceLibcInternal): return the negative zero from fminf for zeros of different sign 2026-10-13 21:12:48 +13:00
jagrat Singh 55ddffe269 feat(libkernel_sys): implement unlinkat 2026-10-13 10:11:24 +02:00
Adrià bd826d52f8
Merge pull request #4816 from winstrex/feat/agc-get-gs-prim-payload
feat(libSceAgc): implement sceAgcGetGsPrimPayload
2026-10-13 10:11:08 +02:00
Dean Galvin 3a9cc63683 fix(libc): hand out the unwind cursor table through a _nid_no_patch export
_Unwind_Context took its cursor table from LibcUnwind::CursorSlots, a C++
data symbol of libc. On Windows LibcUnwind::Frame holds an _Unwind_Context,
so libSceAgcDriver, which builds frames for its worker sampler, imported
_ZN10LibcUnwind11CursorSlotsE from libc.prx. The NID patcher renames that
export in the patched libc and leaves the import alone, so the patched
libSceAgcDriver, libSceAgc and libSceVideoOut failed to load with error 127
and patched_libraries failed. The table is now file-local and the context
reads it through UnwindCursorSlots_nid_no_patch, which keeps its name on
both sides.
2026-10-13 21:09:26 +13:00
Adrià Franch dd5853d8bc docs(debt): cite the source of sceNpEntitlementAccessGetPftFlag 2026-10-13 10:08:30 +02:00
jagrat Singh 7900b59d52 feat(libSceNpEntitlementAccess): implement sceNpEntitlementAccessGetPftFlag
Reports a full game, not a Play First Trial: 0 is written to the uint32_t output and 0 returned; a null pointer returns 0x817D0002.

Signature, value, one-word write and error match sceNpEntitlementAccessGetGameTrialsFlag and sharpemu src/SharpEmu.Libs/Np/NpEntitlementAccessExports.cs:98-116. 0x817D0002 is the parameter error of KytyPS5, prosper and sceNpEntitlementAccessGetEntitlementKey. The library has no initialization state, so none is checked. Update technical debt documentation and add unit test in guest_offline_imports.
2026-10-13 10:08:24 +02:00
Adrià 6e83cad175
Merge pull request #5010 from adriadam10/chore/remove-reactnative-vsh
chore(libs): remove libReactNative.Modules.Vsh and its WebAppLauncher
2026-10-13 10:05:48 +02:00
Adrià Franch ed79ae1a2f chore(libs): remove libReactNative.Modules.Vsh and its WebAppLauncher
They are modules of the console's own shell (VSH), not libraries a title
links. No title in the open PRs, discussions or code references them, and
every export is a stub that throws. Their Share*, ErrorDialog* and
SystemServiceParamGet* exports duplicate libSceShare, libSceErrorDialog
and libSceSystemService (#228, #241).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 10:04:28 +02:00
Adrià c080fc2d5b
Merge pull request #4786 from p3n1cillin/claude/load-exec-restart
feat: convert a title's other executables and start them with sceSystemServiceLoadExec
2026-10-13 10:02:50 +02:00
pushkarreddyy 837c862e22 feat(libkernel): implement sigpending 2026-10-13 13:30:35 +05:30
Adrià 4834930ea6
Merge pull request #4784 from freshstart2066-create/feat/libc-floor
feat(libc): implement floor
2026-10-13 09:59:40 +02:00
MarcZX100 7bb59f73b4 docs(libSceLibcInternal): record spawn import stops 2026-10-13 07:56:19 +00:00
David 2fe382c658 feat(libSceLibcInternal): implement the posix_spawn attribute and file action calls
XPSemu (PPSA97358) imports eleven posix_spawn calls from
libSceLibcInternal.prx, one reference each, and no call site is known.
Predicted stop (import order, not measured), behind isnanf (idx 296):
`FAIL: unresolved ELF import 44hlATrd47U from libSceLibcInternal.prx`
(posix_spawnattr_init, idx 347), followed by p--TkNVsXjA, LG6O0oW9bQU,
Sj7y+JO5PcM, Ud8CbISKRGM, Hq9-2AMG+ks, IUfBO5UIZNc, Heh4KJwyoX8 (348-355),
UV4m0bznVtU, Ani6e+T-y6Q and 3Nr9caNHhyg (379-381).

The nine object calls follow FreeBSD release/11.4.0 (8c639945a445)
lib/libc/gen/posix_spawn.c: posix_spawnattr_init allocates a zeroed
attribute object (ENOMEM on failure), _destroy frees it, _setflags and
_setsigdefault store the value; posix_spawn_file_actions_init allocates an
empty list (-1 on failure, as in 11.4), _destroy frees it with its
entries, and _addopen (path copied), _adddup2 and _addclose append in
order after returning EBADF for a negative descriptor. Null or
uninitialized objects, which FreeBSD dereferences, throw.

posix_spawn and posix_spawnp throw "process creation not implemented",
as execvp does: FreeBSD validates no argument before rfork/vfork, and no
child process can be created here. TechnicalDebt records them.
guest_posix_spawn covers the attribute round trips, the recorded action
sequence, the EBADF cases and the throws. NIDs computed with
tools/nid_names.py and present in aerolib.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 07:56:19 +00:00
Kikoarl 396b5189a9 perf(agc): disambiguate completion label overlaps in CopyBuffer 2026-10-13 09:56:09 +02:00
Adrià 42e5edadbe
Merge pull request #4708 from Aathish-D/feat/savedata-get-convert-progress
feat(libSceSaveData): implement sceSaveDataGetConvertProgress
2026-10-13 09:56:01 +02:00
Adrià 0587a755d6
Merge pull request #4775 from p3n1cillin/claude/pad-angular-velocity-deadband
feat(libScePad): apply the angular velocity deadband
2026-10-13 09:55:21 +02:00
Adrià a527286241
Merge pull request #4743 from jagrat04/feat/libkernel_sys-mkdirat
feat(libkernel_sys): implement mkdirat
2026-10-13 09:55:12 +02:00
eljackjoestar-cmd 68c2b0f746 fix(agc): prioritize demanded shader preparation 2026-10-13 11:54:29 +04:00
p3nicillin 99efb32c40 feat: convert a title's other executables and start them with sceSystemServiceLoadExec
The relinker's repeatable --executable converts another executable of the
title beside the output, sharing its libs, app0 and guest modules.
sceSystemServiceLoadExec maps /app0 paths to those executables, passes the
argument list on the new command line and finds the main executable through
APS5_EBOOT. RetroArch (PPSA99169) starts its frontend picker this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 08:51:50 +01:00
David a7ea2bdcaa feat(libkernel): add mlockall
mlockall (x7g7Ebeo8-U, aerolib) follows FreeBSD 11.4's sys_mlockall
(sys/vm/vm_mmap.c:1067-1131, freebsd-src
8c639945a44588f6cfdddfb057bb5aad88735da0) for the flag check: 0 or
bits outside MCL_CURRENT (1) and MCL_FUTURE (2) fail with EINVAL. The
title process is taken to pass priv_check(PRIV_VM_MLOCK), as mlock
already does.

Valid flags throw. MCL_FUTURE would need every later guest and host
mapping to be locked; nothing in the mapping paths does that, and
passing it to the host would make later host allocations fail above
the host RLIMIT_MEMLOCK. MCL_CURRENT would have to lock the whole
process, which on AnyPS5 also holds host stacks, heaps, modules and
driver mappings (sceKernelVirtualQuery reports them as guest memory),
with ENOMEM above a guest RLIMIT_MEMLOCK that is not known (getrlimit
throws for it). mlock pins host pages (VirtualLock, mlock) range by
range and keeps no record, so there is no state to extend. Recorded
in TechnicalDebt.

XPSemu (PPSA97358) calls it only with -overcommit mem-lock=on
(ZiZc3/XPSemu 8eec07b4, os-posix.c:330-355, reached from
system/vl.c:831-835):

    int flags = MCL_CURRENT | MCL_FUTURE;
    ...
    ret = mlockall(flags);
    if (ret < 0) {
        error_report("mlockall: %s", strerror(errno));
    }

and exits on failure, so that option ends in the throw; without it
the title is not affected. Predicted stop removed (registry index 201,
not run):
FAIL: unresolved ELF import x7g7Ebeo8-U from libkernel.prx

guest_mlock checks EINVAL for 0, 4, 5 and -1 and the throw for 1, 2
and 3.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 87f4aa331b02d098fe27516809495447ff6a9fa6)
2026-10-13 07:51:35 +00:00
Arekatla Nishanth Chowdary ebd71eb2e7 test(libSceRudp): follow the End/Terminate swap in the context query and pump tests
guest_rudp_context_queries released its context with sceRudpEnd(context)
and shut the library down with sceRudpTerminate(), and guest_rudp_pump
shut it down with sceRudpTerminate(), the order main had before the
swap. They now call sceRudpTerminate(context) and sceRudpEnd().
2026-10-13 07:51:20 +00:00
David 4029b5d2c9 fix(libSceRudp): swap sceRudpEnd and sceRudpTerminate
sceRudpEnd takes no argument and shuts the library down; sceRudpTerminate
takes a context id and releases that context. main had the two swapped,
so a title calling sceRudpEnd() passed a stray register as a context id
and the library stayed initialised.

Evidence:
- PS5 console measurement by hugodearaujo in #3073 (firmware 13.60):
  "After `sceRudpEnd()` all three return `0x80770001` again"
  (sceRudpGetMaxSegmentSize, sceRudpProcessEvents, sceRudpNetFlush).
- AlexAltea/orbital cc408367da6a6ebbf5ac1ac559fefeadc73b2831
  tools/ida/db_types.json:1971,1996: `int sceRudpEnd(void)`,
  `int sceRudpTerminate(int ctxId)`.
- RPCS3 26098fb42d090cd522b4afcf3b754dd987c82978
  rpcs3/Emu/Cell/Modules/cellRudp.cpp:108: `cellRudpEnd()` tears the
  library down.
- AndnixSH/Vita3K-PS-Vita-OS-Fork c86ac732bc811057e690bed280c5076bdf95385e
  vita3k/modules/SceRudp/SceLibRudp.cpp:1032,1614: `sceRudpEnd()` clears
  every context, `sceRudpTerminate(int ctx_id)` erases one.

The bodies are unchanged, only exchanged. guest_offline_imports now ends
the library with sceRudpEnd(), and guest_rudp_status checks that
sceRudpTerminate releases one context and sceRudpEnd all of them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 07:51:20 +00:00
MarcZX100 a4752266b8 docs(libc): record Windows directory fopen behavior 2026-10-13 07:51:09 +00:00
MarcZX100 eefe4db018 fix(libc): return native fopen errors 2026-10-13 07:51:09 +00:00
Blazing Cook acd8c8c527 test(ampr): retain both pooled-page ownership regressions
Restore the original alias-remap regression alongside the pool-exhaustion
regression so each ownership fix remains covered after combining the series.
2026-10-13 07:50:53 +00:00
MarcZX100 45a157d931 fix(ampr): reserve remap targets before releasing pool pages 2026-10-13 07:50:53 +00:00
Blazing Cook a88a4c8e15 fix(ampr): reserve targets before releasing mapped pool pages
(cherry picked from commit 3e9a37eaa34c4d543f775bece42de3eb7a4647ea)
2026-10-13 07:50:53 +00:00
Blazing Cook ce98f83033 fix(ampr): retain pooled pages while remapping aliases
(cherry picked from commit a2408b5244c663849ae4f7022e7aff01f2ba5abc)
2026-10-13 07:50:53 +00:00
Aathish b078f475ec feat(libSceSaveData): implement sceSaveDataGetConvertProgress 2026-10-13 09:48:44 +02:00
Adrià fc1f063f51
Merge pull request #4622 from jagrat04/feat/libkernel-lutimes
feat(libkernel): implement lutimes
2026-10-13 09:48:07 +02:00
Adrià a24da90293
Merge pull request #4990 from 0xRickx/fix/libc-dynamic-cast-guest-abi
fix(libc): call __dynamic_cast and __cxa_init_primary_exception with the guest ABI
2026-10-13 09:46:33 +02:00
Adrià 8da50fd052
Merge pull request #4592 from leorossi2005/feat/libkernel_libSceLibcInternal_missing_ppsa99902
feat(libSceLibcInternal): implement fminf required for PPSA99902 startup
2026-10-13 09:46:04 +02:00
Adrià a373241de4
Merge pull request #4582 from jagrat04/feat/libkernel-madvise-madv-protect-pr
feat(libkernel): accept MADV_PROTECT advisory hint in madvise
2026-10-13 09:44:18 +02:00
MarcZX100 3e238ff11d fix(shader): accept MIMG sampler tuples ending in VCC 2026-10-13 07:40:17 +00:00
MarcZX100 8d455b8018 docs(libkernel): qualify atfork title reachability 2026-10-13 07:39:26 +00:00
David e8fd542f03 feat(libkernel): implement pthread_atfork
pthread_atfork (U9t5kJAWPnA, aerolib) appends the prepare, parent and
child handlers to a process-wide list under a lock and returns 0, or
ENOMEM when the entry cannot be allocated, as FreeBSD 11.4's
_pthread_atfork does (lib/libthr/thread/thr_fork.c:78-100, freebsd-src
8c639945a44588f6cfdddfb057bb5aad88735da0). Null handlers are accepted;
FreeBSD's fork skips them. The handlers never run: fork
(libkernel_sys) throws and vfork is absent, so no child process is
created. The list is kept, in registration order, for a later fork
(PthreadAtforkHandlers_nid_no_patch); recorded in TechnicalDebt.

XPSemu (PPSA97358) calls it from a constructor, before main
(ZiZc3/XPSemu 8eec07b4, util/rcu.c:488-495):

    static void __attribute__((__constructor__)) rcu_init(void)
    {
        smp_mb_global_init();
    #ifdef CONFIG_POSIX
        pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_child);
    #endif
        rcu_init_complete();
    }

so a throwing export would stop the title before main. Predicted stop
removed (registry index 255, not run):
FAIL: unresolved ELF import U9t5kJAWPnA from libkernel.prx

guest_pthread_atfork checks registration order, null handlers,
concurrent registration from four threads and that no handler runs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit f37bccf6efd76edcde5d582800c89b83fdd30472)
2026-10-13 07:38:13 +00:00
Rick 7154138369 test(libc): register guest_dynamic_cast beside guest_array_callbacks
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 09:36:52 +02:00
Adrià 6d7b873702
Merge pull request #4945 from nicolasfalesy/fix/libc-unwind-backtrace-cursor
fix(libc): let a title's own libunwind read _Unwind_Backtrace frames
2026-10-13 09:36:45 +02:00
ideabsassistenza 6fb0727c48 fix(debt): preserve leading entries during conflict resolution 2026-10-13 09:34:22 +02:00
Yunus Shaikh 60fb528572 refactor(libSceNet): place the SCE timeout constants and timeout_option apart from new neighbours
#4988 adds a constant after NET_SO_RCVTIMEO and #4989 adds a function before receive_error, so defining the SCE timeout constants and timeout_option there made the pull requests conflict.
2026-10-13 00:34:06 -07:00
David 78ffdf0521 feat(libc): implement wcsftime
PS5MC (PPSA99420) imports wcsftime (XbVXpf5WF28, aerolib) as the last
absent libSceLibcInternal import in its registry order (index 481), so
its predicted stop is:

    FAIL: unresolved ELF import XbVXpf5WF28 from libSceLibcInternal.prx

The stop is predicted from the import order, not observed in a run.

wcsftime follows FreeBSD 11.4 lib/libc/locale/wcsftime.c (8c639945):
the wide format is converted with wcsrtombs, strftime fills a buffer of
maxsize * MB_CUR_MAX bytes limited to maxsize, and mbsrtowcs converts
the result back. A format unit that the single-byte C locale of
lib/libc/locale/none.c cannot encode returns 0 with EILSEQ, a maxsize
whose product with MB_CUR_MAX overflows returns 0 with EINVAL, and an
empty or overflowing result or a null buffer returns 0 with errno
unchanged; the ERANGE or EINVAL set by the Windows CRT's strftime is
discarded. A null format or tm throws, as FreeBSD dereferences it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 07:33:58 +00:00
Adrià 9ba9ac1c8b
Merge pull request #4834 from GoodTimeclubs/feat/exports-ppsa01317
feat(exports): export the calls PPSA01317 imports
2026-10-13 09:33:36 +02:00
MarcZX100 c4a61eae75 docs(agc): document shared view alias coverage 2026-10-13 07:31:42 +00:00
Angel21PC 2d1cc82bce fix(libc): alias non-contiguous shared guest views on Windows
On Windows, a host import of shared guest memory goes through a
read-write alias from WindowsMappings::MapAlias. The alias was a single
MapViewOfFile3 of one section, so MapAlias threw when the views of the
range were not one contiguous run of that section. One
sceKernelMapDirectMemory over two adjacent direct memory allocations
gives such a range, as each allocation has its own section, and so do
pages remapped in place to another physical order.

Such ranges are now aliased run by run: a placeholder reservation is
split at each run of consecutive pages of one section, and each run
maps that section at its offset. UnmapAlias unmaps every run and forgets
the alias even when one unmap fails. A contiguous range keeps the single
view, and a range with a page that is not a shared view is still
refused.

guest_memory maps two adjacent direct memory allocations of two pages
and one page with one call, and two pages in reverse physical order.
It reads and writes every page through the alias. The first test also
checks that the alias has one view per run and that unmapping it frees
its pages. A range whose second page is flexible memory is still
refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit fc6868d8b6fedd0a43987909cadef618f16ada4b)
2026-10-13 07:31:17 +00:00
Adrià 30caf2b2a5
Merge pull request #4682 from bubblegg/feat/netctl-get-if-stat
feat(libSceNetCtl): add sceNetCtlGetIfStat
2026-10-13 09:26:47 +02:00
Adrià 6c87f76b57
Merge pull request #4753 from p3n1cillin/claude/audio-out-ex-monitor-info
feat(libSceAudioOut): list no audio descriptors in sceAudioOutExGetMonitorInfo
2026-10-13 09:26:42 +02:00
Ondra97 74e239408b fix(tools): reject mixed high refresh skip diagnostics 2026-10-13 09:25:12 +02:00
p3nicillin 3292cd39fb feat(libSceSystemService): relaunch the title for sceSystemServiceLoadExec of its own eboot.bin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 08:25:03 +01:00
Ondra97 7ebad36341 fix(tools): accept skips on displays without 120 Hz 2026-10-13 09:19:28 +02:00
babyhuey 0daf1d5ba3 fix(libSceNet): report SO_ERROR from sceNetGetsockopt 2026-10-13 03:15:45 -04:00
Ondra97 6706e44d95 fix(conventions): ignore C++ raw literal contents 2026-10-13 09:15:31 +02:00
Doston Abdullayev 9cdcd58171 fix(libkernel): use precise waits for empty poll sets
Carry the poll-only portion of Doston Abdullayev’s public #1471 fix, preserving its original authorship. The select timeout change is already covered separately by #4754.
2026-10-13 07:11:08 +00:00
Rick f4be0362c8 fix(libc): call __dynamic_cast and __cxa_init_primary_exception with the guest ABI
Every other export of the C++ runtime is declared APS5_VABI, but these two
were not. On Windows a title calls them with the System V convention while
they read the Microsoft one, so __dynamic_cast took its fourth argument, the
src2dst hint, as the source pointer: an ordinary downcast (hint 0) returned
null, and the negative hints made it read through an invalid pointer.

guest_dynamic_cast calls both through APS5_VABI declarations, as a title
does, and checks a single-inheritance downcast, a failed cross cast, a cast
of a base object and the header __cxa_init_primary_exception fills in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 09:10:08 +02:00
Alex Collini a141b8eb67 fix(agc): drop the comment in SrgbTwinFormat
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:09:33 +02:00
TideOPL 007721d43e perf(shader): index specialization tables by SPIR-V id
SpecializeSpirv kept its per-id data (folded values, result types, scalar
types, removed ids, blocks, edges, copies, definitions and the live sets) in
std::map and std::set, and repeats fold, prune and copy propagation over the
whole module until nothing changes. Ids are dense below the header's bound,
so the tables become vectors indexed by id. Lookups of operands that are
literals rather than ids stay bounds-checked, iteration keeps ascending id
order, and an id at or beyond the bound now throws.
2026-10-13 07:59:08 +01:00
Alex Collini 12d07b8edd fix(agc): give R8 and R8G8 no sRGB twin where the device decodes them in the shader
SrgbTwinFormat mapped R8_UNORM and R8G8_UNORM to R8_SRGB and R8G8_SRGB
without asking the device. Where 8_SRGB or 8_8_SRGB is decoded in the
shader (context.srgbDecodeFormats: the device cannot sample the sRGB
format, or APS5_SRGB_SHADER_DECODE=1), the forced view would have been
created with a format the device cannot sample. Those two formats now
get no twin there, so a FORCE_DEGAMMA sampler on them keeps the refusal.
The image is no longer created MUTABLE_FORMAT either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 08:58:19 +02:00
Dean c2565f0149
Merge pull request #4391 from MarcZX100/codex/socket-descriptors-4366
fix(libkernel): give guest sockets ordinary descriptor numbers below FD_SETSIZE
2026-10-13 19:52:08 +13:00
Dean d71423a575
Merge pull request #4911 from oneandonlydean/up4/atomic-buffer-fault-only
perf(shader): record a specialized buffer atomic's fault without the address tables
2026-10-13 19:52:01 +13:00
fdfawef324 0f77f3e07f feat(libSceDbgThreadSanitizer): declare the TSan annotation calls and report the sanitizer disabled
Black Myth: Wukong (PPSA23226) exits at start-up with
STATUS_DLL_NOT_FOUND after "Failed to load module:
libs\libSceDbgThreadSanitizer.prx". The executable does not need the
library: its bundled sce_module/libSceJobManager_nosubmission.prx lists
it in DT_NEEDED and imports __tsan_acquire and __tsan_release from it,
plus sceKernelIsThreadSanitizerEnabled from libkernel. The relinker
converts every module in sce_module and loads it at start-up (only
--module-dir directories are deferred), and GuestModuleBuilder adds each
module's host dependencies to the executable's DT_NEEDED, which the
Windows start-up stub loads.

libSceDbgThreadSanitizer now exports __tsan_acquire and __tsan_release
with the void(void* addr) signatures of LLVM compiler-rt's
tsan_interface.h (llvm-project 87f0227cb601, LLVM 20.1.8). Both throw:
AnyPS5 runs no race detector, and the module calls them only after
sceKernelIsThreadSanitizerEnabled reports the sanitizer enabled.
libkernel's sceKernelIsThreadSanitizerEnabled returns 0, as
sceKernelIsAddressSanitizerEnabled does; its int(void) signature is
assumed and recorded in the libkernel debt file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:12:05 -04:00
hypermist 6bf9ab86ff perf(agc): keep adjacent ranges one import serves as one region of the cached address space
A V# spanning two registered ranges dissolved the shared space into the
build's own regions (about 10k regions copied, sorted and looked up per
build in Killing Floor 3), although the import covering the run binds it
in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo
2026-10-13 19:03:20 +13:00
MarcZX100 c7aca86c61 fix(tools): use the shared merge base for overlap checks 2026-10-13 06:01:10 +00:00
Ondra97 66edc7463f fix(tools): audit stubs from shared library sources 2026-10-13 07:59:10 +02:00
Nicolas Falesy db3ec02c54 fix(libc): let a title's own libunwind read _Unwind_Backtrace frames
Homebrew built with the ps5-payload-dev SDK links LLVM libunwind
statically but imports _Unwind_Backtrace from libSceLibcInternal. Its
trace callback then reads each frame with its own _Unwind_GetIP, which
treats the context as a libunwind cursor and calls through the virtual
table in its first word. AnyPS5's context started with the saved RAX, so
the call jumped to a register value and the title crashed on its error
path (vkQuake, PPSA99010, without its game data). The context now starts
with a table in AbstractUnwindCursor's slot order that answers register
reads and writes, validFloatReg and isSignalFrame; other slots throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EvDbpwUPTa78oCAJqe7m9K
2026-10-13 01:55:14 -04:00
MarcZX100 2a91815210 fix(tools): parse paginated overlap API responses 2026-10-13 05:52:46 +00:00
Dean ea2bbefb2b
Merge pull request #4402 from jakezwang/fix/spirv-redundancy-memory
fix(shader): release bundled optimizer traversal maps
2026-10-13 18:49:45 +13:00
Dean ebf417a51c
Merge pull request #4340 from ArjenS-LA/fix/guest-gnu-hash
fix(relinker): convert guest modules with GNU hash tables
2026-10-13 18:49:38 +13:00
QRMOE 2c23ced70e
test(libc): cover llroundl boundaries in every rounding mode 2026-10-13 07:47:45 +02:00
QRMOE f745a00a5d
fix(libc): accept the full llroundl integer range 2026-10-13 07:46:49 +02:00
LeandroLP23 fa889c063b docs(contributing): ask GPU changes to name the GPUs their tests ran on
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 07:45:50 +02:00
MarcZX100 abc997b0da fix(agc): release cached address space on device teardown 2026-10-13 05:35:37 +00:00
Dean 88107b7de6
Merge pull request #4535 from moong15/codex/windows-deferred-write-watch
fix(agc): defer write tracking for fresh Windows shared imports
2026-10-13 18:33:39 +13:00
Dean Galvin dbe16fb28c perf(shader): record a specialized buffer atomic's fault without the address tables
A program with an atomic on a V# it specializes was compiled as
address-based (usesDma) so that the atomic's unaligned-address check could
call the fault function. The atomic itself goes through the element's
storage buffer and nothing in such a program reads the address tables. In
the driver an address-based build leases all registered guest memory and
binds every V# of the program in place inside a host import, so none of
its elements is staged in device memory, the atomic one included.

The atomic now asks for the fault buffer alone (usesFaultBuffer) and
records the fault through RecordBdaFaultWords, which has both forms. The
fault record, the stop of the invocation and the atomic are unchanged. The
64-bit fault address needs shaderInt64, as the scalar buffer load does. A
tessellation-control program with such an atomic is refused as before.

Test: agc_shader_memory compiles a buffer_atomic_inc on a specialized V#
and requires no address table binding, one fault buffer, one call of the
fault function, logical addressing and the atomic element flag; without
shaderInt64 the program is refused.
2026-10-13 18:29:59 +13:00
Dean 2cc97e1057
Merge pull request #4197 from MarcZX100/codex/audit-coredump-userdata
feat(libkernel): implement coredump user data calls
2026-10-13 18:24:28 +13:00
babyhuey d39cb2c62f feat(libkernel): report machdep.tsc_freq from sysctlbyname 2026-10-13 01:18:43 -04:00
umang b24e1cc46f perf(agc): return from fresh Windows collection when nothing is fresh
MarkWritten collects the fresh portions of the written blocks before
each GPU stamp. On Windows that walked every shared view of those
blocks twice under the mappings mutex even when all of them had been
collected before. Keep the never-collected portions as address ranges,
as the Linux tracker keeps _fresh, and return after one lookup when
none overlaps the request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:37:27 +05:30
umang b14d087cd4 fix(agc): defer write tracking for fresh Windows shared imports 2026-10-13 10:37:27 +05:30
MarcZX100 c1bcd0b697 fix(videoout): dump linear display buffers 2026-10-13 05:05:31 +00:00
Dean 7e181fcc38
Merge pull request #3874 from oneandonlydean/up4/import-window-compare
perf(agc): compare an import window's pages when the window closes
2026-10-13 17:55:13 +13:00
Dean 597f976872
Merge pull request #3947 from MarcZX100/codex/carry-getsockname-unbound
fix(libkernel): return the zero address for unbound getsockname on Windows
2026-10-13 17:54:53 +13:00
Dean 3cfb915cf0
Merge pull request #4187 from Scramblrrrr/codex/cpu-copy-profile-spans
fix(agc): profile completed CPU copies with their actual spans
2026-10-13 17:54:30 +13:00
Dean e268844924
Merge pull request #4700 from Nesyth/fix/agc-comp-to-single-dcc-reads
fix(agc): read comp-to-single DCC keys of sampled textures and storage images
2026-10-13 17:54:09 +13:00
Dean 52edeeda5d
Merge pull request #4698 from Nesyth/perf/libc-shared-lease-snapshot
perf(libc): share one snapshot of the registered guest ranges between leases until the registry changes
2026-10-13 17:53:47 +13:00
Dean fa39549b50
Merge pull request #4654 from GustavoGamarra95/fix/agc-store-pending-under-written-buffers
fix(agc): store pending storage results before a use writes the same memory as a buffer
2026-10-13 17:53:26 +13:00
Dean 7e2a2ae5f9
Merge pull request #4363 from johnmaia/fix/gpl-shader-rendering
fix(agc): build pipeline library shader parts for the draw's depth format
2026-10-13 17:53:05 +13:00
Dean f9821b76ed
Merge pull request #4097 from kr4y4/fix/shader-f16-ternary-output-modifier
fix(shader): keep the output modifier of the f16 min3, max3, med3 and div_fixup ops
2026-10-13 17:52:50 +13:00
Dean 547807422c
Merge pull request #3471 from Kikoarl/perf/agc-copied-writes-overlap
perf(agc): disambiguate direct GPU writes from copied write-backs in indirect draws
2026-10-13 17:52:29 +13:00
Dean fe8d3eba0e
Merge pull request #3633 from tv7/fix/color-view-array-slice-range
fix(agc): render a color view of several array slices into its first slice
2026-10-13 17:51:58 +13:00
Dean 46e7cd3e83
Merge pull request #4838 from milescoviello/carry/seek-pipe-stream-windows-4837
fix(libc): fail fseek and ftell on a pipe with ESPIPE on Windows
2026-10-13 17:51:37 +13:00
Dean 9b7c8ea965
Merge pull request #4811 from milescoviello/carry/localtime-range-windows-4807
fix(libc): convert local times before 1970 and after 3000 on Windows
2026-10-13 17:51:16 +13:00
Dean e15c316ead
Merge pull request #4733 from fdfawef324/fix/libc-collate-char-capacity
fix(libc): size collate<char>::do_transform strings as the console does
2026-10-13 17:50:55 +13:00
Dean 1268ba8cd4
Merge pull request #4727 from gjonn/feat/hull-dynamic-control-point-index
feat(shader): read hull inputs at a control-point index computed from data
2026-10-13 17:50:35 +13:00
Dean e64bf3c5d0
Merge pull request #4662 from fdfawef324/fix/agc-gpu-map-import-off-guest-stack
fix(agc): import GPU-mapped memory on a host stack
2026-10-13 17:50:12 +13:00
Dean a6ed539e70
Merge pull request #4659 from AaravMehta-07/codex/sce-pthread-sem-overflow
fix(libkernel): guard SCE pthread semaphore count overflow
2026-10-13 17:49:51 +13:00
Dean b7025517e1
Merge pull request #4656 from milescoviello/fix/rwlock-writer-preference
fix(libkernel): hold back new rwlock readers while a writer waits
2026-10-13 17:49:30 +13:00
Dean 4fe3123627
Merge pull request #4640 from MarcZX100/codex/win-host-standard-handles-4631
fix(libc): preserve host standard handles on Windows redirects
2026-10-13 17:49:02 +13:00
Dean 88f48fddef
Merge pull request #4688 from eliyarson/fix/kernel-stat-relinked-prx
fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
2026-10-13 17:48:42 +13:00
Dean 73a5f3a41c
Merge pull request #4667 from babyhuey/feat/libkernel-sysctl-hw-model
feat(libkernel): report hw.model from sysctl
2026-10-13 17:48:21 +13:00
Dean 2ffbb75ae7
Merge pull request #4206 from jweidenh/codex/sparse-buffer-hole-initialization
fix(agc): clear interior holes in recycled sparse buffers
2026-10-13 17:48:00 +13:00
Dean 432675d919
Merge pull request #4252 from karanvora2599/perf/shader-wave32-exec-lane-bits
perf(shader): keep wave32 EXEC and VCC lane bits without a ballot round trip
2026-10-13 17:47:39 +13:00
Dean 02f5c0bcb0
Merge pull request #4195 from rugbedbugg/fix/shader-narrowing-fold
fix(shader): preserve integer narrowing in constant folding
2026-10-13 17:47:18 +13:00
Dean 887953200b
Merge pull request #4248 from hypermoist/perf/guest-buffer-region-index-sort
perf(agc): sort guest buffer regions through indices before merging them
2026-10-13 17:47:05 +13:00
Dean cc55e1410a
Merge pull request #4661 from fdfawef324/fix/libc-shared-write-pages
fix(libc): track writes to shared guest memory per 4 KiB page on Windows
2026-10-13 17:46:44 +13:00
Dean 61e4b5506c
Merge pull request #4017 from jweidenh/codex/host-import-submission-lifetime
fix(agc): defer host import retirement until the GPU lock is held
2026-10-13 17:46:23 +13:00
screamm c8379be922 feat(libkernel): implement the coredump user-data calls
sceCoredumpWriteUserData (Dbbkj6YHWdo) and sceCoredumpDebugTextOut
(dei8oUx6DbU) get the signatures of Orbital's db_types.json (cc408367)
and SharpProspero's KernelSystem.cs (5dfdb4b0): ssize_t (const void*,
size_t) and void (const char*, int). WriteUserData moves out of
Unimplemented.cpp.

User data belongs to the core dump handler: the Vita's
sceCoredumpWriteUserData returns 0x800A0003 ("No user-data capture is
active") outside it (vita-headers e66ebe90), and the RED engine's PS4
crash handler makes every coredump call from its handler (Vangaurd
4f86d2b0). The handler is never invoked here, so WriteUserData returns
SCE_COREDUMP_ERROR_NOT_IN_COREDUMP_HANDLER (0x81180003, shadPS4
coredump_error.h e0a46675) sign-extended and keeps nothing; a null,
empty or wrapping buffer throws because the order of the console's
checks is unknown. DebugTextOut prints its text to stderr with the
[coredump] prefix; a negative length or a null text with a nonzero
length throws.

Evidence: Broken Sword Reforged (PPSA21480) reaches the family through
its sibling, #3704 comment 6113687542: "`ERROR agc_graphics.cpp:266
Sony call failed with code 8a6c9018` (the resource registration error,
followed by the error dialog), then `sceCoredumpWriteUserString not
implemented`." WriteUserString has no declaration in any source and
keeps throwing; its TechnicalDebt entry records the call. 007 First
Light (PPSA11386) imports WriteUserData (#2523) without calling it
before its stop.

Test: guest_coredump_user_data.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 04:43:50 +00:00
David 097bc538ee fix(libkernel): fail ftruncate on a pipe, a directory and a device with EINVAL on Windows
(cherry picked from commit 971fb51ef3f09d6543ef20e05e4a44572d2aadbd)
2026-10-13 04:18:07 +00:00
Feuris ab4ccade2c feat(libc): implement _Mtx_init_with_name 2026-10-13 01:05:37 -03:00
Hussein Kadhim 0438621d74 fix(libkernel): getsockname on an unbound socket returns the zero address on Windows
FreeBSD's in_getsockaddr and in6_getsockaddr succeed for a socket that has no
local address and return the wildcard address with port 0. Winsock fails
getsockname with WSAEINVAL until the socket is bound, which the guest saw as
EINVAL. Return the zero address of the socket's family for that error.
2026-10-13 17:01:30 +13:00
Dean e51428bf23
Merge pull request #4759 from fdfawef324/fix/bda-span-read-split
fix(shader): split a BDA span read's in-place loads from its fallback
2026-10-13 17:00:47 +13:00
David 2f1eb100a0 fix(libkernel): fail reads on a directory descriptor with EISDIR on Windows
(cherry picked from commit d7ef271ef7eeb1d82a337a0b0a9767ce68721bd4)
2026-10-13 04:00:38 +00:00
Dean 226b40db0f
Merge pull request #2132 from Raghav314/fix/agc-msaa-fill-clear
fix(agc): clear a multisampled target on a uniform fill of its color memory
2026-10-13 17:00:26 +13:00
Dean 3fed8e9bf3
Merge pull request #2121 from Raghav314/fix/agc-cb-resolve-source-samples
fix(agc): take a CB resolve's sample count from its source target
2026-10-13 17:00:06 +13:00
Dean 3779597778
Merge pull request #4658 from milescoviello/fix/sockopt-option-lengths
fix(libkernel): accept socket option values longer than an int
2026-10-13 16:53:12 +13:00
Dean 675c52ca98
Merge pull request #4580 from coltken95/fix/shader-same-target-branch
fix(shader): never branch conditionally to one label twice
2026-10-13 16:52:48 +13:00
Dean a675333d5a
Merge pull request #4600 from coltken95/fix/shader-folded-continue
fix(shader): keep the back-edge of a loop whose continue block is dead
2026-10-13 16:52:24 +13:00
Dean 3a0642e131
Merge pull request #4019 from ahir061/fix/macos-shader-cache-directory
fix(shader): find the shader cache directory on macOS
2026-10-13 16:52:01 +13:00
Dean 0d54077b9a
Merge pull request #4500 from ee6aba54/feat/agc-depth-surface-storage
feat(libSceAgcDriver): storage image access to depth surfaces
2026-10-13 16:50:53 +13:00
milescoviello 7cba4ce60a fix(libkernel_sys): let link follow a symbolic link like FreeBSD
link threw "a symbolic link as the existing path is not supported" when
its first argument named a symbolic link, so a valid call aborted the
title. FreeBSD's link follows that link (sys/kern/vfs_syscalls.c,
sys_link: "kern_linkat(td, AT_FDCWD, AT_FDCWD, uap->path, uap->link,
UIO_USERSPACE, FOLLOW)") and hard-links the file it points to; a link to
a directory then fails with EPERM ("if (vp->v_type == VDIR) ... return
(EPERM);") and a dangling one with ENOENT from namei.

link now checks the followed status of the existing path and, when it
is a symbolic link, creates the hard link to the file it resolves to.
std::filesystem::create_hard_link would otherwise link the symbolic
link itself on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a521101b77c879234308711c5ec8a9f9cf00816f)
2026-10-13 03:46:17 +00:00
Dean 6124bf063f
Merge pull request #4907 from oneandonlydean/up4/fix-msaa-guest-access-segv
fix(agc): submit tiled multisample test targets before destroying them
2026-10-13 16:40:11 +13:00
MarcZX100 e0ec0c8094 fix(libkernel): route equeue socket checks by membership 2026-10-13 03:28:27 +00:00
Nithishvelan M a479fcd737
fix(libScePngDec): validate this_size on create
- Return SCE_PNG_DEC_ERROR_INVALID_SIZE when PngDecCreateParam::this_size does not match sizeof(PngDecCreateParam), matching libSceJpegDec behavior.
- Add test coverage for invalid create parameter size.
2026-10-13 08:55:25 +05:30
xXPBSXx 67e7a3029c fix(agc): decode primitive type 3 as a line strip
DecodeState mapped points, lists, strips, fans, rect lists and patches
but threw "unsupported primitive type 3" for VGT_PRIMITIVE_TYPE 3, the
line strip (DI_PT_LINESTRIP in Mesa's r600d.h). Record of Lodoss War
(PPSA05347) stops on it after a few minutes.

Vulkan allows primitive restart for line strips without the list
restart extension, and the precheck, the pipeline and the provoking
vertex check already treat the strip class that way; only the decode
lacked the case. The point and line depth bias enable stays rejected on
line strips like on line lists, and a line strip gets the line primitive
class for a pixel shader that reads the ancillary word.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 05:23:21 +02:00
MarcZX100 eb2b360f0b fix(libkernel): route updated socket descriptors by table 2026-10-13 03:22:38 +00:00
MarcZX100 c33036eefe fix(libkernel): return bad descriptor from fstat 2026-10-13 03:22:38 +00:00
MarcZX100 488e18691a fix(libkernel): route socket options by table membership 2026-10-13 03:22:38 +00:00
screamm e99816e8f3 fix(libkernel): give guest sockets ordinary descriptor numbers below FD_SETSIZE
libkernel numbered guest sockets from GuestSockets::FirstDescriptor
(0x10000000), so a title that puts a socket in a 1024-bit fd_set writes
fd / 8 bytes past it. The Epic Online Services SDK does this on its
RtcNetworkThread and three titles stop there (#1794):

Palworld PPSA23126 (queeeef, main a11c8f7f7):
  FATAL: unhandled exception 0xc0000005 on thread 37164 'RtcNetworkThread'
    rip 0x00007ffcdb1ea2be eossdk-ps5-shipping.prx.guest.prx+0xdea2be
    rcx 0000000010000005 rsi 0000000000400000 r12 0000000010000005
The Mound PPSA26223 (xXPBSXx, main 0a8b1d32b):
  FATAL: unhandled exception 0xc0000005 on thread 'RtcNetworkThread',
  rip eossdk-ps5-shipping.prx.guest.prx+0xefc6f4, rcx = 0x10000005,
  rsi = 0x400000
Dying Light 2 PPSA02262 (tv7):
  FATAL: unhandled exception 0xc0000005 on thread 'RtcNetworkThread'
    rcx 0000000010000005 ... rsi 0000000000400000 ... r12 0000000010000005

On FreeBSD 11.4 (8c639945) FD_SETSIZE is 1024 (sys/sys/select.h:58-59)
and sockets take the lowest free entry of the one process descriptor
table that files use (kern_descrip.c:1643-1660 fdalloc,
uipc_syscalls.c kern_socket through falloc).

Every socket number is now a real host descriptor: a zero-access NUL
handle registered with _open_osfhandle on Windows (as directory
descriptors already are) and an F_DUPFD_CLOEXEC duplicate of the host
socket on Linux. The socket table maps that number to the socket, so
"is this a socket" is a table lookup instead of a range check at the 31
former FirstDescriptor comparisons. close releases both the socket entry
and the number, dup and dup2 duplicate the number through the host table
and keep the socket shared, dup2 of a file onto a socket number drops the
socket entry, and sceKernelClose now closes sockets too. sceNetSocket and
sceNetAccept take their ids from the same table instead of a counter from
32, so libkernel and libSceNet numbers never collide.

select polls guest sockets alongside libSceNet sockets, the random device,
stdio and (on Linux) host descriptors; poll throws only for an open
descriptor that is not a guest socket and reports POLLNVAL otherwise.
File calls that used to fail with EBADF on the socket range return
FreeBSD's answer for a socket: lseek ESPIPE (kern_lseek), ftruncate and
getdirentries EINVAL (invfo_truncate, getvnode), flock EOPNOTSUPP;
fstat on a socket throws. pread on a closed descriptor returns EBADF.

title failing on host descriptor numbers; these three titles are that
case, and this change keeps host numbering for files and only moves
sockets into it.

Tests: guest_socket_descriptors (new: socket below 1024, select on a
socket and a file together, close frees the number for a file, dup of a
socket, sceKernelClose), guest_select (socket and pipe together, Linux),
guest_poll, guest_dup, guest_socket_pair, guest_fstatfs,
guest_posix_filesystem and guest_sce_net updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 20378375b31eb5db922db6e55f45e44a4dae6445)
2026-10-13 03:22:36 +00:00
Dean Galvin b32ba9eeef fix(agc): submit tiled multisample test targets before destroying them
The tiled cases of agc_multisample_guest_access destroyed each target while its layout transition and clear were still recorded, so the recorder later submitted commands for destroyed images and lavapipe crashed executing them. Each case now submits and waits first, as the linear case does. The 2x case runs only when the device renders 2x color, like the 8x case.
2026-10-13 16:07:32 +13:00
Nicolas Falesy 6f284b8298 feat(libSceVideoOut): implement sceVideoOutDeleteVrrActiveStatusEvent
The NID -q-vbO859Tw, declared as sceVideoOutUnknown_q_vbO859Tw for
PPSA02530, hashes to sceVideoOutDeleteVrrActiveStatusEvent. It removes the
handle's VRR status registration from the queue like the other Delete*Event
calls, the counterpart of sceVideoOutAddVrrActiveStatusEvent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WeVmjnnPPKdxVTpr2Vjtw
2026-10-12 23:04:58 -04:00
Gjon Gojcevic 63ed0ffeaf feat(agc): sample the base level through unnormalized samplers
The hardware ignores the LOD for unnormalized coordinates and samples the
base level. A sampler used only by explicit-LOD, implicit-LOD, bias and
gradient samples gets a pipeline specialization constant set from its
unnormalized bit when the binding plan is prepared. When the constant is
set, each of its samples is emitted as OpImageSampleExplicitLod with LOD 0,
which is what Vulkan requires of unnormalized samplers. Otherwise the
sample keeps its own form. Such shaders are no longer refused.
2026-10-12 22:58:16 -04:00
Dean Galvin e322c6e064 fix(agc): a pending CMASK clear takes precedence over a refused color fill
ApplyFastClear took the color fill before the CMASK clear, so a partial
fill of a multisampled target's color memory threw at the next use even
when a CMASK fast clear was pending over the whole target. The CB reads
a cleared tile's color from the clear registers whatever the memory
holds, so the CMASK clear is applied and the recorded fill dropped.
2026-10-13 15:48:03 +13:00
raghav314 d57f9cfb03 fix(agc): take a CB resolve's sample count from its source target
DecodeColorMetadataPass treated a CB_COLOR_CONTROL resolve as one only
when PA_SC_AA_CONFIG has a sample count, and checked the source against
it. A title that resolves with the rasterizer single-sample fell through
to the draw path and threw "only normal color rendering with copy ROP is
supported (... mode resolve)".

A color target's sample count is CB_COLOR_ATTRIB.NUM_SAMPLES, separate
from the rasterizer's; radeonsi itself writes PA_SC_AA_CONFIG 0 for a
multisampled framebuffer when rasterizer multisampling and line
smoothing are off. So a resolve is decoded when either the rasterizer or
CB0 is multisampled, and its sample count is CB0's. When the rasterizer
is multisampled, the source still has to match it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:46:45 +13:00
Yunus Shaikh d6698c9045 refactor(agc): declare maxDrawSnapshotBytes after guestMemory
#757 and #758 add a member after usesFaultBuffer, so declaring maxDrawSnapshotBytes there made the pull requests conflict.
2026-10-12 19:43:34 -07:00
milescoviello 0dda76b1f9 fix(libc): check for a pipe on every stream seek on Windows
The pipe check cached its first answer in the FileStream, so a stream
first used on a regular file stayed classified as a file after its
descriptor was replaced with a pipe (dup2 onto fileno(stream)), and a
later fseek reached the C runtime again and dropped buffered bytes.
fseeko and ftello now ask GetFileType on each call, as lseek on a pipe
does since #4670, and FileStream no longer keeps the state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:38:02 +00:00
David 7aabb9005c fix(libc): fail fseek and ftell on a pipe with ESPIPE on Windows 2026-10-13 02:38:01 +00:00
Dean c13dc7e6b4
Merge pull request #4558 from MiniRML/fix/kernel-json-number-locale
fix(kernel): parse JSON numbers independently of host locale
2026-10-13 15:37:49 +13:00
Dean 417c7d02a7
Merge pull request #4586 from ee6aba54/fix/agc-lookahead-write-data
fix(agc): count every CP data write of a dispatch group as a write of the run
2026-10-13 15:37:38 +13:00
Dean 7cad853fc1
Merge pull request #4690 from David-cmrg/fix/libkernel-create-data-dir
fix(libkernel): create /data at start-up
2026-10-13 15:37:26 +13:00
Dean bef5f45bbc
Merge pull request #4729 from zaydzaari/research/rtc-minute-separator-1342
fix(rtc): reject date strings ending at the minutes
2026-10-13 15:37:15 +13:00
Dean b85934913f
Merge pull request #4738 from milescoviello/carry/fdopen-append-windows-4735
fix(libc): append through a descriptor opened by fdopen in an append mode on Windows
2026-10-13 15:37:03 +13:00
Dean b17fb4a4a7
Merge pull request #4792 from marshmll/fix/linux-host-stderr-redirect
fix(libc): keep host diagnostics on stderr when a guest redirects it on Linux
2026-10-13 15:36:51 +13:00
Dean 255a91abd6
Merge pull request #4809 from MarcZX100/codex/unaligned-shader-abi-4782
fix(agc): accept unaligned shader headers in ABI resolution
2026-10-13 15:36:40 +13:00
Dean 1419ea91fd
Merge pull request #3958 from MarcZX100/codex/carry-accepted-socket-mode
fix(libkernel): inherit listener mode on accepted sockets
2026-10-13 15:36:27 +13:00
Dean 834de1ab10
Merge pull request #4199 from sanxchep/fix/msaa-guest-guard
fix(agc): size multisample guest guards by fragment blocks
2026-10-13 15:36:14 +13:00
Dean 37a0a3608c
Merge pull request #4480 from milescoviello/carry/fcntl-record-locks-windows-4479
feat(libkernel): implement fcntl record locks on Windows
2026-10-13 15:36:03 +13:00
Dean 495bf91a04
Merge pull request #4880 from David-cmrg/fix/libc-mspace-realloc-usable
fix(libc): keep a moved mspace block's usable bytes in realloc
2026-10-13 15:15:29 +13:00
Dean Galvin f15671ecf3 fix(agc): copy the depth plane again after a storage write
A sampled copy of a depth plane is kept while the surface's write
serial is unchanged. Storing a written storage view back into the
depth image did not bump the serial, so a later draw or dispatch that
sampled the plane as an array or cube kept the values from before the
store. The store-back bumps it now.

The dispatch test samples the plane through a copy, stores to it in a
dispatch and samples it again.
2026-10-13 15:00:36 +13:00
Dean Galvin 738ae9df06 test(agc): cover depth storage access through dispatches
Draw depth and stencil, read and rewrite each plane in compute
dispatches, and check the stored values with depth-tested and
stencil-tested draws, a following dispatch and the flushed guest bytes.
The array view, multisampled and two-view refusals are checked through
dispatches as well.
2026-10-13 15:00:36 +13:00
Dean Galvin 889e5d436a fix(agc): refuse depth storage views the plane copy cannot serve
A 2D array or cube view with the plane's extent and format reached the
ordinary path and read guest bytes the depth was never written to; it
throws again, with the message main has for it. A multisampled surface
is refused before the plane copy, as sampling it already is. A written
view that another view of the same plane replaced had its results
dropped at store-back; that throws now.

Update the debt entry to what is supported and what still throws.
2026-10-13 15:00:36 +13:00
Simon 7d06be06f0 fix(libSceAgcDriver): refuse storage access to a widened D16 depth plane
A D16_UNORM_S8_UINT surface is stored as D24_UNORM_S8_UINT or
D32_SFLOAT_S8_UINT on devices without the 16-bit format. Copying its
depth aspect yields 4 bytes per texel, so the 16-bit storage image of
the depth plane would receive the wrong layout. Such an access now
throws, naming the surface and both formats; the stencil plane keeps
its 8-bit layout and stays supported.
2026-10-13 15:00:36 +13:00
Simon 27e1122774 feat(libSceAgcDriver): storage image access to depth surfaces
Compute shaders bind the depth and stencil planes of a depth surface as
storage images, to read the depth or to write it before later draws
test against it. The driver kept depth on the GPU and refused such
bindings.

A depth surface now owns one storage image per plane (R32_SFLOAT or
R16_UNORM for depth, R8_UINT for stencil). Binding copies the plane
into it through a staging buffer; a written element is copied back into
the depth image during write-back, so the next draw sees the shader's
depth.

A view whose extent differs from the surface's means the memory was
reused for another texture and takes the ordinary texture path; this
applies to sampled views of a depth surface too.

PPSA15304 copies depth and stencil through storage images every frame.
2026-10-13 15:00:36 +13:00
David 69b9d186db fix(libc): replace an open or read-only destination in rename on Windows 2026-10-13 05:58:01 +04:00
Dean 37dd483084
Merge pull request #4468 from GustavoGamarra95/perf/agc-capture-one-sync-per-run
perf(agc): wait once per unit run when a storage image captures its guest bytes
2026-10-13 14:54:24 +13:00
Dean 2a55cfe1e8
Merge pull request #2491 from oneandonlydean/up639/depth-plane-unchanged-copy-on-425
perf(agc): skip the depth plane copy when no slice changed
2026-10-13 14:49:05 +13:00
Dean 26f8047889
Merge pull request #2490 from oneandonlydean/up639/depth-plane-guest-layers-on-425
perf(agc): keep unchanged guest layers of a depth plane copy
2026-10-13 14:48:43 +13:00
Dean c27687313c
Merge pull request #4859 from EagleBearerYS/fix/libkernel-flexible-map-flag-8000
fix(libkernel): accept flag 0x8000 in sceKernelMapFlexibleMemory
2026-10-13 14:48:21 +13:00
Dean 048206e18c
Merge pull request #4410 from MarcZX100/codex/idle-results-debounce-4398
fix(agc-driver): delay storage writeback until queue activity settles
2026-10-13 14:48:00 +13:00
Dean c3625c4789
Merge pull request #4120 from tibzejoker/fix/vector-window-direct-ssa
fix(shader): keep direct VGPR accesses in SSA when the window has only relative reads
2026-10-13 14:47:39 +13:00
David 7126090654 fix(libc): convert local times before 1970 and after 3000 on Windows 2026-10-13 01:47:03 +00:00
David-cmrg 00c35c159c fix(libc): keep a moved mspace block's usable bytes in realloc 2026-10-13 03:38:29 +02:00
Dean Galvin 50e5f088c9 perf(agc): skip the depth plane copy when no slice changed
Sampling a depth array, cube or R16_UINT view of depth surfaces went
through DepthPlaneCopy::Refresh on every use. Each use copied every slice
a depth surface holds into the staging buffer and the whole staging buffer
into the copy image, with three ALL_COMMANDS barriers, although nothing
had written the slices since the previous use.

Each depth surface now carries a write serial, bumped when a draw binds it
as its depth target and when a pending fast clear is applied. The copy
keeps the image and serial of every slice it copied. A use copies only the
slices whose surface or serial changed and the guest layers that changed
(as before), and records nothing when none did. A slice whose surface is
the depth target of the latest depth draw is copied at every use until
another depth target is bound, since that draw may still be recorded after
the copy.

Test: agc_driver_depth_plane_guest_layers counts the recorded slice copies
and copy fills; a second use with nothing written records none (it records
one of each without this change), a draw to a slice's surface or a CPU write
to a guest layer copies only that layer.
2026-10-13 14:33:40 +13:00
raghav314 1baf077a7e fix(agc): clear a multisampled target on a uniform fill of its color memory
A multisampled target's samples live only in its host image, so a fill
of its color memory never reached them: a title that clears its MSAA
targets that way (with no CMASK) kept drawing over the previous frame.

A uniform fill over the whole color memory now clears the host image to
that value at the target's next use, the same way a CMASK fast clear
does, and a pending CMASK clear still takes precedence. The color memory
is sized with addrlib's block dimensions for the sample count
(ComputeThinBlockDimension): a 64 KiB block holds width x height x
samples elements, laid out width first for 1x and 4x. A fill over part
of it, over a target whose footprint is not computed, or with a value
that has no exact clear value in the format throws at the next use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 07:01:57 +05:30
Dean 0c3dc9ca2b
Merge pull request #4381 from Celegans12/fix/agc-aliased-buffer-views
fix(agc): accept aliased views of the guest buffers in graphics shaders
2026-10-13 14:31:53 +13:00
Dean 22c30bed2b
Merge pull request #4842 from LeandroLP23/fix/agc-ancillary-layer-unwritten
fix(shader): read the ancillary render target index as 0
2026-10-13 14:31:32 +13:00
lorkydey c18daed286 fix(libkernel): validate CPU stop-info buffers and cover handler state 2026-10-13 03:21:58 +02:00
poonasor 02ed289566 feat(libkernel): implement sceCoredumpGetStopInfoCpu
PPSA34063 (NHL 27) calls it with a 16-byte buffer outside a coredump
handler and expects 0x81180003 there. The registered handler is never
invoked, so every call is outside one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d04f5d600e52372b968ce0f06139f519fe068724)
2026-10-13 03:18:53 +02:00
Dean d1fd9372ba
Merge pull request #3602 from CouchRiv/fix-libc-powf-special-value
fix(libc): powf(1, y) returns 1 for any y
2026-10-13 14:15:52 +13:00
Dean 9ddb59fb87
Merge pull request #3635 from MarcZX100/codex/libc-readdir-r-3556
feat(libc): implement readdir_r
2026-10-13 14:15:32 +13:00
Dean Galvin d9c0407391 test(shader): make the read-only window tests pass in the full Linux build
With SPIRV-Tools enabled the optimizer replaces a window that is only
indexed by constants with scalars, so the sampler spill case found no
array. It now reads M0 from the thread group id, as the first case does.

The direct access test reads and writes lanes across a wave32, which a
device with 8-lane subgroups cannot hold; it skips there like the
v_readlane and v_writelane tests.
2026-10-13 14:09:05 +13:00
jagrat Singh 8d08caa529 feat(libkernel): implement lutimes 2026-10-13 06:29:45 +05:30
thibaut c87f3771d1 test(shader): let direct SSA mirrors of a read-only window pass the stage input check
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-13 13:59:35 +13:00
thibaut efa96f73bc test(shader): check direct and relative reads of a read-only vector window on the GPU
Write window registers directly (VALU, v_writelane_b32, buffer load,
v_movrels_b32 results), read them back directly and through
v_movrels_b32 at several M0 values, including after a direct rewrite,
and feed a v_readlane_b32 of the written lane into the output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-13 13:59:35 +13:00
thibaut ebf939ff10 test(shader): cover a sampler spilled through a read-only vector window
A compute program reads v4 relatively with v_movrels_b32, spills sampler dword
0 into v4 with v_writelane_b32, restores it with v_readlane_b32 and samples
with it. On main the restore reads the window array and resource analysis
refuses GetSamplerResource with ReadLane(LoadVectorWindow(Immediate),
Immediate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-13 13:59:35 +13:00
thibaut 2ecbbe40a3 fix(shader): keep direct VGPR accesses in SSA when the window has only relative reads
A program that uses relative VGPR addressing placed every register from the
lowest relatively addressed one upward in the window array, so even direct
accesses became array loads and stores. A descriptor spilled with v_writelane
and restored with v_readlane then lost its definition, and resource analysis
refused GetSamplerResource with ReadLane(LoadVectorWindow(Immediate)) (GTA V,
PPSA04264, shader 0x25a889400).

When the program has no indexed writes (v_movreld, v_movrelsd, v_swaprel),
direct accesses stay SSA registers and each direct write is mirrored into the
window for the relative reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-13 13:59:35 +13:00
Dean 510a2188cf
Merge pull request #4031 from AlxcBTW/carry/pixel-ancillary-word-v3
feat(shader): give reads the masked-select pass keeps the whole pixel ancillary word
2026-10-13 13:59:10 +13:00
Dean 4430780bdd
Merge pull request #3644 from DariusHQ/fix/libkernel-poll-pipes
fix(libkernel): poll pipe descriptors
2026-10-13 13:52:54 +13:00
Sanxchep Sharma 8bcf1cc0df fix(agc): size multisample guest guards by fragment blocks 2026-10-13 02:52:51 +02:00
Dean 007759a6b6
Merge pull request #4524 from jagrat04/feat/libkernel-segment-info
feat(libkernel): implement sceKernelInternalMemoryGetModuleSegmentInfo
2026-10-13 13:52:34 +13:00
Yunus Shaikh 4ccf888291 fix(savedata): leave the mount result untouched when sceSaveDataMount3 fails
Animal Well (PPSA22520) checks for its save with a CREATE2 mount it never
unmounts, then saves with a second mount of the same directory. That
mount returns BUSY, and the title keeps using the first mount point for
sceSaveDataPrepare, its save file and sceSaveDataUmount2.
sceSaveDataMount3 cleared the result before its checks, so the save was
written to "/save" in the game folder instead of the save directory, and
the first mount was never released. The result is now written only when
the mount succeeds, as shadPS4 does.
2026-10-12 17:47:46 -07:00
jagrat Singh ec0d61e58e feat(libkernel_sys): implement mkdirat 2026-10-13 06:11:56 +05:30
Gustavo Ariel Gamarra Rojas e260f24939 test(agc): refuse committed reads of a multisampled target's memory
The multisampled target guest access test now also reads the target's
memory through ReadCommitted and ReadCommittedUnsynced and expects both
to throw.
2026-10-12 21:41:23 -03:00
Gustavo Ariel Gamarra Rojas fa28772174 fix(agc): run the read guard in a committed read without the flush hook
ReadCommittedUnsynced skipped the read guard ReadCommitted runs before its
flush hook, so a storage image capture over a multisampled target's
memory read the bytes instead of throwing. Both reads now run the guard,
ReadCommitted still before its flush hook, and share the copy.
2026-10-12 21:41:23 -03:00
Dean 758aca7373
Merge pull request #4116 from hawwwwwk/investigate/relinker-eip-relative
fix(relinker): resolve EIP-relative imports in strict filter
2026-10-13 13:41:08 +13:00
Dean Galvin 64ca6e3329 fix(libkernel): follow pollscan for a pipe whose other end is closed
FreeBSD's pollscan clears POLLOUT whenever POLLHUP is set, so a write end
whose read end is closed reports POLLHUP alone, with POLLIN and POLLRDNORM
when they were asked for; both host paths reported POLLOUT | POLLHUP.

POLLOUT on a read end now throws. FreeBSD opens both ends FREAD | FWRITE
and pipe_poll reports the read end writable, which a one-way host pipe
cannot back.

guest_poll drained 1 KiB from the full pipe before expecting POLLOUT, but
Linux reports it only once a whole 4 KiB page is free, so the test aborted
there. It now drains the pipe, which is writable on every host.
2026-10-13 13:37:28 +13:00
Dean 284a1c3342
Merge pull request #4509 from ErenYeager1836/feat/webbrowser-dialog-predetermined-content
fix(libSceWebBrowserDialog): permit termination from finished state in sceWebBrowserDialogTerminate
2026-10-13 13:34:24 +13:00
Dean 1b360faa1d
Merge pull request #4441 from superhe11/codex/fix-elf-header-validation
fix(relinker): validate the ELF object version and header size
2026-10-13 13:34:03 +13:00
Alex a3b8c054f3 fix(libc): powf(1, y) returns 1 for any y
powf(1.0, nan) returned 0x7fc00001; FreeBSD msun (lib/msun/src/e_powf.c)
returns 0x3f800000. That case now follows FreeBSD; other inputs are
unchanged.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-12 20:32:48 -04:00
David 665e6f1782 fix(libkernel): fill every buffer of readv from a pipe on Windows 2026-10-13 00:30:45 +00:00
TideOPL 126a1e4137 perf(agc): copy a pending block-compressed surface into its sampled texture on the GPU
A compute pass can write a block-compressed surface through an uncompressed
storage view whose element is one block (32_32_UINT for 8-byte blocks,
32_32_32_32_UINT for 16-byte ones). cachedTexture rejected such a storage
image for the BC descriptor, so every sample stored the whole surface to
guest memory, compared it with the snapshot and uploaded it again.

Texture::CanBlockCopyFrom accepts a storage image over the same memory,
tiling and swizzle whose element is the block and whose extent is the
surface's extent in blocks, with whole blocks on every copied level. The
sampled texture then owns a BC image that vkCmdCopyImage refreshes from the
storage image when its version moved, through the same refreshed-on-reuse
path as the depth copy.
2026-10-13 01:29:21 +01:00
babyhuey c15e9f2a37 fix(libSceVideoOut): return RESOURCE_BUSY when a bus is opened twice 2026-10-12 20:26:26 -04:00
LeandroLP23 3334e41e45 fix(shader): read the ancillary render target index as 0
No pre-rasterization stage writes Layer: vertex layer exports are
ignored, so the first layer is used and the render target index field
of the packed ancillary word is 0. The lowering read the Layer builtin
for it instead. AMD's Windows driver drops the color writes of a
fragment shader that consumes an unwritten Layer, which made
agc_driver_relative_ancillary fail on AMD hardware (#4800); lavapipe
returns 0 there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:23:56 +13:00
Cesar Rodriguez baaad78e81 fix(agc): leave blending off for a color target with CB_COLOR_INFO.BLEND_BYPASS
DecodeState threw "blend bypass conflicts with enabled blending" when
CB_BLENDn_CONTROL enabled blending for a target whose CB_COLORn_INFO has
BLEND_BYPASS (bit 16, Mesa src/amd/registers/gfx10.json) set. The bit makes
the color block skip the blender for that target: Mesa sets it "according
to docs" for UINT/SINT and 8_24/24_8/X24_8_32_FLOAT targets, which the
blender cannot process (src/amd/common/ac_descriptors.c, shared by radeonsi
and RADV). Marvel's Guardians of the Galaxy (PPSA01748) issues such draws
right after its loading screen. Blending is now enabled only when it is
requested and not bypassed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:22:38 -07:00
Dean Galvin c52321fab5 fix(shader): move the primitive class to request version 19 and compose the ancillary word with render target index 0
main reads target.vertexSubgroups at request version 18 since #4470, so
reading the pixel primitive class at 18 as well read a version 18
request written by main one byte short. The class is now written and
read at version 19. agc_shader_memory loads a version 18 request as
main writes it, and it fails with "truncated data" when the class is
read at 18.

The composed word no longer reads the Layer builtin for bits 16-28.
Draws render to a single layer and guest layer exports are ignored, so
no stage writes Layer, and AMD's Windows driver drops the writes of a
fragment shader that reads it unwritten (#4800). The field is the
constant 0 and pixel_ancillary checks that the composed program has no
Layer read. The debt entry names the bits that have no source and are
assumed zero (2-7, 12-15, 29-31), and says that a change which makes
draws export a layer must restore the read.
2026-10-13 13:18:51 +13:00
Simon 51c043ba51 fix(agc): keep the texels of CMASK tiles with codes other than 0 and 15
A fast-clear materialization threw when a CMASK nibble held a code other
than 0 (cleared) or 15 (expanded). PPSA18391 (engine: Clickteam Fusion) fast
clears a target whose CMASK it never initialized, so some nibbles hold
leftover values such as 1 and 10, and presentation failed on the first
frame.

Such a tile now keeps its texels like an expanded tile, on the CPU path
and in the compute pass. A cleared tile of a DCC target still throws.
The graphics and CMASK fast-clear tests now check that an unknown code
leaves the tile unchanged instead of expecting the throw.
2026-10-13 02:17:33 +02:00
Celegans12 d644c31855 fix(agc): accept aliased views of the guest buffers in graphics shaders
The SPIR-V emitter declares extra views of the guest buffers binding:
buffers_coherent for GLC or DLC accesses (#2369) and buffers_u64 for
64-bit atomics. Each is another StorageBuffer variable on the same set
and binding, decorated Aliased, which Vulkan allows.

ShaderValidation, which checks the stages of every draw, accepted one
StorageBuffer variable per binding with u32 elements only, so such a
graphics shader was refused with "duplicate SPIR-V resource binding".

A second variable is now accepted when the binding is the guest buffers
array and every variable on it is Aliased; an aliased view may hold u64
elements. Other duplicates are still refused. agc_driver_graphics
validates pixel shaders with a GLC store and a 64-bit atomic, and checks
that the same modules without Aliased are refused.
2026-10-13 02:15:38 +02:00
AlxcBTW d0aca69eff test(agc): a relative read of the whole ancillary word gets the composed word
The relative-ancillary test expected the whole-word read through
v_movrels to be refused, which was main's behaviour before the word was
composed. It now converts that read to float and exports it: the
composed word of a triangle draw is 2 (primitive class 2, sample 0,
layer 0), so the pixel is 255, with and without the implicit position
inputs in front of the ancillary VGPR. TechnicalDebt's relative
addressing entry no longer says that whole-word uses throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:06:27 +13:00
AlxcBTW 18d9874a06 feat(shader): give reads the masked-select pass keeps the whole pixel ancillary word
A packed ancillary word that still reaches an export, or any other read
the masked-select pass cannot drop, no longer stops the recompile. After
that pass every remaining use gets the composed word: the primitive class
at bits 0-1, SampleId at bits 8-11 and Layer at bits 16-28, with every
other bit zero. Those lanes do export the ancillary VGPR on the console,
so the word has to be right, not just present.

The primitive class (0 point, 1 line, 2 triangle, 3 rectangle) comes from
the draw. RasterPrimitiveOf maps rect lists to 3, line lists on the vertex
path to 1 and everything else the driver accepts to 2, because its
geometry and tessellation paths only output triangles. It reaches the
shader as pipeline specialization constant 8233, the way dual-source
blending does: a request field that is folded into the specialized
module and is part of the result memo, the draw key and the serialized
request (version 17).

Only shaders that read the class pay for it. ShaderInfo records the read
(disk cache format 28), and only those shaders put the class in their
module key, so a shader that reads just the sample or layer field keeps
one module for every primitive class. The draw sets the class only when
the pixel shader loads the ancillary VGPR, so other draws keep the draw
cache entries they have today.

The VRS rates (bits 2-5) and the eye id (bit 7) are 0 because the driver
supports neither VRS nor multiview. SampleId is 0 because the driver
rejects MSAA and per-sample shading, and Layer is 0 while it ignores
vertex layer exports. TechnicalDebt.md records the layout sources and
these assumptions.

Tests:
- pixel_ancillary builds an export to target 0 whose two channels select
  between a packed value and a phi carrying the word. It checks the word
  for each primitive class, sample and layer, checks that the three
  shapes the masked-select pass keeps now compile with the composed word,
  and that a program whose select the pass drops reads no class.
- agc_driver_pixel_ancillary_word exports the word from a draw and reads
  back 2, 3 and 1 for triangle, rectangle and line. A shader that reads
  only the sample field shares one module across the classes, and the
  whole-word shader gets one per class. It also checks RasterPrimitiveOf.
- agc_shader_memory covers the version 17 round trip, and
  agc_shader_disk_cache the new flag.

Both ancillary tests fail with the old refusal when the composition is
disabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:06:21 +13:00
Dean Galvin af7160475b perf(agc): keep unchanged guest layers of a depth plane copy
Sampling a depth surface as a 2D array, a cube or its integer bits
copies its planes into a per-use image. Each use read every slice no
depth surface holds from guest memory and detiled it again, even when
nothing had written it since: in one level of a heavier title that was
about 165,000 layer reads, about 650 GiB, in a five-minute run.

A slice read from guest memory now stays in the copy's staging buffer
with the write generation it was read at. The next use reads and
detiles it again only when its address, size or tiling changed, the
write tracker reports a write since, or recorded GPU work writes the
range; a slice a depth surface held in between is read again. Without
write watching every use reads, as before.
2026-10-13 12:59:26 +13:00
Dean 1c5e62878a
Merge pull request #425 from MichonGoddijn231849/feat/depth-surface-reads
feat(agc): depth planes sampled as 2D arrays, cubes and integer views
2026-10-13 12:58:34 +13:00
Dean e55b881f0f
Merge pull request #4598 from Lorkydey/feat/ngs2-listener-transform
feat(libSceNgs2): support default listener calculation
2026-10-13 12:56:18 +13:00
Dean 056d17ecc5
Merge pull request #3816 from alfalfa-star/fix/agc-htile-memory-value-fill
fix(agc): take an HTILE fill from a value in memory as a depth fast clear
2026-10-13 12:46:38 +13:00
alfalfa-star fd98327ba7 fix(agc): take a memory value fill only when the hardware stores the raw value
The kernel reads its value with s_buffer_load_dword through the V# in
user[4..7] and stores it with buffer_store_format_x through the V# in
user[0..3]. When the value V# covers less than a dword (NUM_RECORDS
times its stride, or NUM_RECORDS bytes for stride 0) the load returns 0,
and a store format other than 32_UINT, 32_SINT or 32_FLOAT converts the
value, so in both cases the HTILE does not receive the dword read from
memory. The match now requires both. Kena's own dispatch (format
32_UINT, a value V# of one 16-byte record) still matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:40:31 +13:00
alfalfa-star d31b13f491 fix(agc): take an HTILE fill from a value in memory as a depth fast clear
PPSA01802 (Kena: Bridge of Spirits) clears its depth HTILE every frame
with its own compute kernel: a 9-word dword fill that stores, through
the stride-4 V# in user[0..3], a value loaded from the pointer in
user[4..5]. Neither the DMA_DATA hook nor the fill kernels the driver
recognizes saw it, so the depth kept the first frames' contents and the
base pass and sky failed their depth test almost everywhere.

The kernel is matched exactly when the dispatch is decoded, the value is
read from guest memory, and the range is passed to NoteDepthMetadataFill
like a fill, so the whole-HTILE and ZMask rules apply unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:40:24 +13:00
Dean e6ecece94e
Merge pull request #4267 from EagleBearerYS/fix/shader-color-compare-8bit-unorm-zero
fix(shader): return 0 for 8-bit UNORM color comparison
2026-10-13 12:38:49 +13:00
Yunus Shaikh 584c59e5ac test(libkernel): compare the unterminated readv buffer with memcmp 2026-10-12 16:37:56 -07:00
john.maia 0900586191 feat(agc): skip the draws and dispatches of one shader with APS5_SKIP_SHADER
APS5_SKIP_SHADER=<code address, hex> drops every draw that runs a program
at that address and every dispatch of a compute program at that address, as
if the packet had run. Skipping one pass at a time shows which pass first
writes a wrong value into an image: Epic Mickey's (PPSA15657) green sky
light was bisected this way to the copy into its sky cube (#4551).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:35:38 +01:00
Dean d38d98bc84
Merge pull request #4068 from Kikoarl/feat/sysmodule-acm-module-id
feat(libSceSysmodule): register libSceAcm (0x10B) and libScePsml (0x137) module IDs
2026-10-13 12:28:42 +13:00
Dean Galvin 90d899d982 fix(agc): first-slice view of depth plane arrays, refuse plane copies of another host format
A 2D-array T# over a depth surface bound to a shader image declared 2D had
no first-layer view, so the descriptor got a null view and the shader read 0.
The depth plane texture now creates the 2D view of its first slice when its
view is a 2D array, for the depth image itself and for the plane copy.

A 16-bit depth surface with stencil may be stored as D24_UNORM_S8_UINT or
D32_SFLOAT_S8_UINT. The plane copy sizes and copies slices by the guest
format, so several slices or an R16_UINT view of such a surface now throw.
2026-10-13 12:18:50 +13:00
MarcZX100 cbd615bb42 fix(agc): return error for unsupported init versions 2026-10-12 23:15:39 +00:00
GoodTimeclubs 8a7e1195d4 feat(exports): export the calls PPSA01317 imports
Gran Turismo 7 (PPSA01317) fails to load on unresolved imports and on
two needed libraries that AnyPS5 does not build (#4782).

- sceAppContentDownloadDataFormat empties /download0, as
  sceAppContentTemporaryDataFormat does for /temp0.
- sceNpAuthSetTimeout returns REQUEST_NOT_FOUND for an unknown request
  like the other request calls, and OK otherwise; no request reaches the
  network the timeouts would bound.
- sceNpWebApi2PushEventSetHandleTimeout throws for an unknown library
  context, like sceNpWebApi2GetMemoryPoolStats, and returns OK
  otherwise; push event handles are not tracked and nothing waits on
  one offline.
- sceSslDisableVerifyOption, sceSslGetAlpnSelected, sceSslSetAlpn,
  sceSslSetMinSslVersion, sceAudioOutDeviceIdOpen and the unnamed
  libScePsml NIDs xNZM9Y5lf-M and lcZD9tJraAw are declared without
  parameters and throw; their signatures are unknown.
- libSceUsbStorage and libSceUsbStorageDialog exist with no exports,
  like libSceXml: the title lists both as needed but imports nothing
  from them.

Each assumption is recorded in the library's technical debt file.

Co-authored-by: dawid-swiecicki <8942606+dawid-swiecicki@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:11:29 +02:00
Michon dc0c2cf8c6 test(agc): agc_driver_depth_plane_sampling pins the sampled plane values
image_load of row 0 through each view, against a live surface drawn at a
known depth and guest-memory slices filled with known values: a 3-slice
D32 2D array, a D32 cube (all six faces), a D16 plane as R16_UINT, and a
D16 depth-bits R16_UINT array (both slices' raw values). A plane array
from base slice 1 is still refused. Fails on main (the array is refused)
and without the depth-bits format gate (GTA V's refusal message).
2026-10-13 12:11:02 +13:00
Michon 086f7d5091 feat(agc): depth planes sampled as 2D arrays, cubes and integer views
A texture over a depth surface could only sample one 2D slice of the
plane's own format; 2D arrays, cubes and the R16_UINT view of a D16
plane were refused ("sampling the depth plane of depth surface ... is
not implemented"). A one-slice 2D array now views the depth image as an
array. Several slices, a cube, or an integer view of a D16 plane are
copied into a DepthPlaneCopy image at every use: each slice from the
depth surface bound at its address (base plus one 64 KiB-block depth
slice per layer), otherwise from guest memory, detiled. A depth-bits
R16_UINT view (a depth swizzle) keeps the depth copy, since the shader
converts the sampled depth to its bits itself (GTA V's compute
0x242d4a200 samples a D16 plane array that way, reported by
@tibzejoker). Such a texture is not kept in resource templates.

Storage-image access to depth surfaces is no longer part of this
change; #4500 implements it.

TechnicalDebt (Depth plane copies) and ARCHITECTURE describe the copy and
what still throws.
2026-10-13 12:11:02 +13:00
Nesyth c809601df8 test(agc): sample comp-to-single keys stored over a pending storage image 2026-10-13 01:04:31 +02:00
Dean 90c683946f
Merge pull request #4819 from oneandonlydean/up4/fix-kqueue-test-flake
fix(libkernel): pair the inotify halves of a rename in a watched directory
2026-10-13 12:03:30 +13:00
jagrat Singh ea03a22c7f feat(libkernel): implement sceKernelInternalMemoryGetModuleSegmentInfo 2026-10-13 04:29:25 +05:30
Dean Galvin 59fcdea9c4 fix(libkernel): pair the inotify halves of a rename in a watched directory
inotify queues IN_MOVED_FROM and IN_MOVED_TO of a rename one after the
other. The watcher thread could read the first before the second was
queued and report a rename inside the directory as a move to another
directory (NOTE_WRITE | NOTE_EXTEND instead of NOTE_WRITE), which made
guest_kqueue abort on loaded runners.

The watcher now reads the queue until it is empty and, when a move half
has no partner, calls getdents64 on the directory before reading again:
that takes the directory lock rename holds until both halves are queued.
2026-10-13 11:53:02 +13:00
jagrat Singh 59bd0c1782 feat(libkernel): accept MADV_PROTECT advisory hint in madvise 2026-10-13 04:21:59 +05:30
winstrex 44debb29b6 docs(debt): record the sceAgcGetGsPrimPayload search and null pointers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:46:20 -03:00
winstrex cb6866653c feat(libSceAgc): implement sceAgcGetGsPrimPayload
Report the 8-byte GS primitive payload when the shader's context registers
set SPI_SHADER_IDX_FORMAT.IDX0_EXPORT_FORMAT to SPI_SHADER_2COMP, and 0
otherwise. The search runs over every context register, so an earlier
SPI_SHADER_IDX_FORMAT entry with another format does not end it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:46:20 -03:00
Yunus Shaikh 56d35172f5 fix(libkernel): accept flag 0x8000 in sceKernelMapFlexibleMemory
The libc.prx heap that Animal Well (PPSA22520 01.000.011, SDK 9.04)
bundles maps each arena with sceKernelMapFlexibleMemory(&addr, len, 3,
0x8000). It threw "Unsupported memory mapping flags 0x8000" before the
first frame. The flag is ignored as sceKernelMapNamedFlexibleMemoryInternal
already does; other unknown flags still throw.
2026-10-12 15:38:48 -07:00
MarcZX100 1988607409 test(agc): cover unaligned shader ABI headers 2026-10-12 22:28:55 +00:00
dawid-swiecicki f838fba198 fix(agc): accept unaligned shader headers when resolving shader ABIs
Gran Turismo 7 (PPSA01317) passes shader headers at 4-byte aligned addresses to
sceAgcUnknownCreateInterpolantMapping. RegisterShader already reads them through a
copy (#902); ResolveShaderAbi, ResolveGraphicsStagesAbi, ResolveGraphicsAbi and
RegisteredHeader still required 8-byte alignment and threw "null or misaligned
address". Read the fixed fields through GuestShaderFields at those sites.
2026-10-12 22:24:52 +00:00
ArjenS-LA 819c475266 fix(tools): match explicit trace summaries to their capture 2026-10-12 15:18:16 -07:00
Dean 43e3a70f81
Merge pull request #4356 from MarcZX100/codex/serialize-load-sensitive-tests
test(cmake): serialize load-sensitive Windows tests
2026-10-13 11:17:40 +13:00
Dean acf1dd7900
Merge pull request #4510 from simonbronk/fix/relinker-weak-imports
fix(relinker): keep weak undefined imports weak
2026-10-13 11:17:25 +13:00
Dean 62b9e7043c
Merge pull request #4362 from krishalivaibhav/codex/recorded-clear-barrier
fix(agc): align recorded fast-clear access scopes
2026-10-13 11:17:10 +13:00
Dean df5108f90e
Merge pull request #4530 from babyhuey/feat/libkernel-internal-memory-available-size
feat(libkernel): export sceKernelInternalMemoryGetAvailableSize
2026-10-13 11:16:17 +13:00
Yunus Shaikh 92e0970d6c test(libSceNet): run CheckUnboundSocketName before CheckUnspecifiedIpv6
#4785 calls its netstat check right after CheckPoolStats(), so calling CheckUnboundSocketName() there made the two pull requests conflict.
2026-10-12 15:11:43 -07:00
Yunus Shaikh a7e320d1f7 test(libSceNet): define CheckEpollWritable after CheckMessages
#4785 adds its netstat checks before CheckPoolStats, so defining CheckEpollWritable there made the two pull requests conflict.
2026-10-12 15:09:09 -07:00
fdfawef324 1eb13fdf02 fix(libc): track writes to shared guest memory per 4 KiB page on Windows
Writes into shared (direct) guest memory on Windows are caught by write
protecting each 16 KiB view and taking the fault. The fault reopened
and invalidated the whole view, so a collect reported all four 4 KiB
pages of a view whenever any byte of it was written, including pages
nobody wrote. A GPU surface that ends or starts inside such a view
then had its edge pages taken for CPU writes whenever the title wrote
the memory next to it, and the storage write-back kept the guest's
stale bytes there instead of the GPU's results.

Each view now keeps a write generation, a seen generation and the
write protection per 4 KiB page. A fault invalidates and reopens only
its page, a host write only the pages it covers, and a collect reports
and re-arms only the pages it covers. VirtualProtect is called once
per contiguous run of pages whose protection changes, so arming or
pinning a view takes one call when those pages are contiguous and two
when they are not. A guest store that fills a whole view takes up to
four faults instead of one.

A collect does not settle a page that it cannot write protect because
a host write is open on one of the page's views; it reports the page
again until a collect can arm it. main settled such a page and relied
on the end of the host write invalidating the whole view, so a guest
store into it during the host write was reported only after the host
write ended. With only the written pages invalidated there, the store
would not be reported at all.

A collect that runs out of room partway through a view now settles the
pages it already reported there and nothing after them; before, it
settled none of them and reported them again at the next collect.

CheckSharedWritePages writes one byte into the second 4 KiB page of a
view and requires a collect of the view's last two pages to report
nothing; main reports both. It also checks a store across two pages
and a file read into one page. CheckSharedWritesDuringHostWrite stores
into a fault-opened page of a view after a collect while a host write
is open on another page of it, and requires every collect of the view
and of its alias to report that page until the host write has ended.
agc_shared_write_partial_collect resets the two interior pages of a
view after writes to all four and requires the outer two to stay
pending. The existing shared-memory checks in guest_memory,
agc_shared_write_partial_collect and guest_socket_host_write (the
recvfrom sender outputs) now expect the pages written instead of the
whole view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:03:53 -04:00
marshmll 438d410824 fix(libc): keep host diagnostics on stderr when a guest redirects it on Linux
On Linux a guest stderr redirect also moves the host's: guest
descriptors are host descriptors, and the guest stderr stream wraps the
host stderr FILE. After dup2(fd, 2), or freopen(path, mode, stderr) with
full buffering, the libc terminate report, the host fprintf(stderr)
diagnostics and libstdc++'s terminate message go into the title's pipe
or file, and abort() discards what is still buffered. RetroArch
(PPSA99169) reopens stderr onto app0/trace.txt with full buffering, so
its stop on main left no message anywhere.

Before the first guest redirect of descriptor 2 (libkernel dup2, libc
freopen of a stream on descriptor 2), keep a close-on-exec duplicate of
the host descriptor 2 and point the host stderr at an unbuffered stream
on it. The guest stream keeps its own FILE and follows the redirect.
The libc terminate report writes to the kept descriptor with write()
instead of the stderr stream, and libkernel's sceKernelDebugOutText uses
the same kept descriptor.
2026-10-12 19:00:08 -03:00
Adrià ee49621900
Merge pull request #4787 from adriadam10/ci/api-budget
ci: cache the API state of the hourly workflows
2026-10-12 23:54:10 +02:00
Adrià Franch 4d15207553 ci: cache the API state of the hourly workflows
pr-overlap and area-labels walked every open PR on each run, spending the
1000 requests/hour that GITHUB_TOKEN gets per repository and starving the
other workflows (HTTP 403 'rate limit exceeded for installation').

pr-overlap keeps a hash of each report in actions/cache and only reads the
comments of PRs whose report changed. area-labels keeps head SHA plus the
labeler.yml blob per PR and labels only the changed ones, at most 40 per
run. conflict-label gets a concurrency group so pushes in a row don't stack
full passes.
2026-10-12 23:49:09 +02:00
BIGFERRY999 f8e2c6497b feat(libc): implement floor 2026-10-12 22:43:46 +01:00
Dean 8a67eb2e68
Merge pull request #4456 from Mouhand-Kaddo/fix/agc-library-used-descriptor-sets
fix(agc): retain used descriptor sets in pipeline libraries
2026-10-13 10:41:32 +13:00
Simone ad0d478a81 Merge remote-tracking branch 'origin/main' into fix/relinker-weak-imports
# Conflicts:
#	core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp
#	core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp
2026-10-12 23:40:54 +02:00
p3nicillin 1d115b8962 feat(libScePad): apply the angular velocity deadband
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:29:57 +01:00
krishalivaibhav 0b54425e3f test(agc): remove non-discriminating recorded clear fixture 2026-10-13 02:57:39 +05:30
Leonardo 02d1dbb9f3
feat(libSceLibcInternal): implement fminf required for PPSA99902 startup 2026-10-12 23:27:13 +02:00
David c22654102b fix(libc): keep the host standard handles when a guest replaces descriptor 0, 1 or 2 on Windows 2026-10-12 21:23:00 +00:00
Adrià 584cc4c571
Merge pull request #4761 from p3n1cillin/claude/agc-driver-validation-debug
feat(libSceAgcDriver): answer validation and shader debugging queries as the retail library does
2026-10-12 23:22:01 +02:00
Adrià 55b2b332c3
Merge pull request #4766 from p3n1cillin/claude/libc-heap-report-for-game
feat(libc): report heap backtraces and heap errors requested by the guest heap
2026-10-12 23:21:56 +02:00
Adrià d7323df946
Merge pull request #4755 from ivica00/feat/libc-nearbyint
feat(libc): implement nearbyint
2026-10-12 23:21:19 +02:00
Adrià Franch 91bad2fce5 test(libSceAudioOut): drop sceAudioOutExGetMonitorInfo from the not-implemented test
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 23:19:02 +02:00
p3nicillin e284717ebe feat(libSceAudioOut): list no audio descriptors in sceAudioOutExGetMonitorInfo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:19:02 +02:00
babyhuey ff56dadc0a feat(libkernel): export sceKernelInternalMemoryGetAvailableSize 2026-10-12 17:18:53 -04:00
Adrià 559979dc67
Merge pull request #4750 from p3n1cillin/claude/session-signaling-connection-status
feat(libSceNpSessionSignaling): answer connection status queries offline
2026-10-12 23:18:08 +02:00
Adrià ceb6927888
Merge pull request #4671 from jagrat04/feat/libkernel-killpg
feat(libkernel): implement killpg
2026-10-12 23:17:33 +02:00
p3nicillin d3ef2b30b7 feat(libc): report heap backtraces and heap errors requested by the guest heap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:15:55 +01:00
Adrià b5b33511f7
Merge pull request #4710 from babyhuey/feat/libkernel-scekernelmmap
feat(libkernel): export sceKernelMmap
2026-10-12 23:15:49 +02:00
Adrià 962aba18f5
Merge pull request #4578 from jagrat04/feat/libkernel-getsid
feat(libkernel): implement getsid for calling process
2026-10-12 23:14:58 +02:00
Niko 7f39ac991b fix(conventions): keep #### subsections inside the pull request template sections
SECTION matched every heading that starts with ###, so a #### line opened
a new section named "# ...". A Tested section written as #### Linux and
#### Windows subsections was reported as missing or empty, and an
unchecked item after a #### line in Checklist was not reported.

A level-4 heading belongs to the level-3 section above it (CommonMark
4.2), and silent_stub_debt() already keeps deeper headings inside their
section. SECTION now matches only headings with exactly three #.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:14:49 +02:00
ArjenS-LA d31e283088 fix(libkernel): throw for unsupported directory entry names 2026-10-12 21:14:01 +00:00
Adrià Franch 53fc059af7 docs(technical-debt): record sceNetCtlGetIfStat assumptions
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 23:13:54 +02:00
bubblegg a2e97d25a6 fix(libSceNetCtl): read 64-bit interface byte counters on Linux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:13:54 +02:00
bubblegg ec07f5a5ec fix(libSceNetCtl): keep the Linux interface counters to Linux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:13:54 +02:00
bubblegg 46338a981c feat(libSceNetCtl): add sceNetCtlGetIfStat
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:13:54 +02:00
Adrià e0fad55e56
Merge pull request #4651 from ErenYeager1836/feat/libkernel-event-error
feat(libkernel): implement sceKernelGetEventError
2026-10-12 23:13:34 +02:00
lorkydey dadc23a8c1 fix(libSceNgs2): reject unverified listener transforms 2026-10-12 23:12:40 +02:00
Adrià 4fc51fd991
Merge pull request #4590 from AlxcBTW/feat/perf-template
docs: add a performance report issue form and ask for summary lines
2026-10-12 23:11:53 +02:00
ivica00 5883c25552 feat(libc): implement nearbyint
The float helper is already on main. The double helper rounds with the current mode and does not raise the inexact flag.
2026-10-12 23:11:50 +02:00
Adrià Franch 935e7d6ba1 test(libkernel): drop guest_ioctl_getsid, it pinned the getsid throw 2026-10-12 23:11:21 +02:00
jagrat Singh 3ce13e2b7d feat(libkernel): implement getsid for calling process 2026-10-12 23:11:21 +02:00
jagrat Singh f08dc5e3c3 feat(libkernel): implement killpg 2026-10-12 23:11:01 +02:00
p3nicillin 8e5a1cae23 feat(libSceAgcDriver): answer the validation and shader debugging queries as the retail library does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:10:58 +01:00
lorkydey 4168cf3bbd feat(libSceNgs2): calculate the listener coordinate transform 2026-10-12 23:10:42 +02:00
Adrià 7940cacd83
Merge pull request #4655 from milescoviello/feat/libc-ceil
feat(libc): implement ceil
2026-10-12 23:10:14 +02:00
Adrià 6d2f279863
Merge pull request #4607 from yunusshaikh7/feat/tracy-profiler
feat(agc): report performance timer scopes to Tracy with APS5_ENABLE_TRACY
2026-10-12 23:09:21 +02:00
Dean 16cdf635e2
Merge pull request #4746 from oneandonlydean/up4/fix-arena-hole-test-flake
test(agc): reserve the arena host hole the write-tracking checks query
2026-10-13 10:08:48 +13:00
Adrià 5efd09afc4
Merge pull request #4653 from Lorkydey/feat/libc-statvfs
feat(libc): query filesystem statistics by guest path
2026-10-12 23:08:17 +02:00
David a0a238c86a feat(libkernel): implement sceKernelGetEventError
Return the event's data when EV_ERROR is set in its flags and 0 otherwise, as KytyPS5 does and as FreeBSD 11 kevent stores the errno of a failed change. A null event throws like the other accessors.
2026-10-12 23:07:39 +02:00
Adrià 5f01c80821
Merge pull request #4595 from jagrat04/feat/libkernel-setregid
feat(libkernel): implement setregid
2026-10-12 23:06:27 +02:00
Adrià 2a9068b159
Merge pull request #4138 from VitzS7/fix/libkernel-signal-waits
feat(libkernel): wait for pending guest signals in the signal waits
2026-10-12 23:06:25 +02:00
p3nicillin b9e9187cfc docs(debt): cite ASTRO BOT's call to sceNpSessionSignalingGetConnectionStatus
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:05:40 +01:00
p3nicillin 3fa1fe34c9 feat(libSceNpSessionSignaling): answer connection status queries offline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:05:23 +01:00
Adrià d415ce7b59
Merge pull request #4220 from xXPBSXx/fix/savedata-dir-name-search2
feat(libSceSaveData): answer sceSaveDataDirNameSearch2
2026-10-12 23:04:55 +02:00
PrintOrb 5031432db0 test(audioout): detect overlapping backend initialization 2026-10-12 16:04:06 -05:00
Adrià 5ccb19b2a0
Merge pull request #4101 from xXPBSXx/fix/kernel-page-table-stats
fix(libkernel): answer sceKernelGetPageTableStats
2026-10-12 23:02:33 +02:00
Dean 6f438a1c2e
Merge pull request #4318 from Amoenus/codex/fix-color-target-d64-x
feat(agc): support 64 KiB display XOR color targets
2026-10-13 10:01:57 +13:00
Adrià dabaaa7def
Merge pull request #3611 from nicolasfalesy/feat/libkernel-pathconf
feat(libkernel_sys): implement pathconf
2026-10-12 23:01:45 +02:00
Dean 38772ed8b2
Merge pull request #4498 from milescoviello/fix/udp-unspec-disconnect
fix(libkernel): dissolve a UDP association on connect to AF_UNSPEC
2026-10-13 10:01:24 +13:00
Dean d3f275a0e6
Merge pull request #4429 from babyhuey/feat/libc-prosperoai-math
feat(libc): implement expm1f, erff, lgamma and llroundl
2026-10-13 10:01:12 +13:00
Dean 7ac3f460e5
Merge pull request #3952 from xXPBSXx/fix/recompiler-resource-control-flow
fix(recompiler): leave out descriptor sources behind a branch the capture decides
2026-10-13 10:00:59 +13:00
Dean 15f3aeaa93
Merge pull request #3883 from hansjm10/feat/agcdriver-get-hs-offchip-param
feat(libSceAgcDriver): export sceAgcDriverGetHsOffchipParam
2026-10-13 10:00:46 +13:00
Dean 22bb451c9f
Merge pull request #3799 from xXPBSXx/fix/export-ppsa02530-imports-v4
fix(exports): export the calls PPSA02530 imports
2026-10-13 10:00:34 +13:00
Adrià 28c9dae73d
Merge pull request #4569 from pipe1os/feat/libkernel-fdopendir
feat(libSceLibcInternal): implement fdopendir
2026-10-12 23:00:17 +02:00
Adrià 4998307175
Merge pull request #4218 from Mouad-Scriptz-0/feat/signin-dialog-npauth-signed-out
feat(libSceNpAuth): return the signed-out error from sceNpAuthGetAuthorizedAppCode
2026-10-12 23:00:04 +02:00
Dean 307c0a3afb
Merge pull request #3819 from xXPBSXx/fix/export-ppsa29866-imports-v4
fix(exports): export the calls PPSA29866 imports
2026-10-13 09:59:30 +13:00
xXPBSXx 989504ed84 feat(libSceSaveData): answer sceSaveDataDirNameSearch2
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:59:26 +02:00
Adrià 158cdcc9b7
Merge pull request #4549 from Nixitov/feat/libc-nearbyintl
feat(libc): implement nearbyintl
2026-10-12 22:58:29 +02:00
Adrià 14db08435f
Merge pull request #3747 from semirkabir/feat/ult-queue-optparam
feat(libSceUlt): accept option parameters in sceUltQueueCreate and sceUltQueueDataResourcePoolCreate
2026-10-12 22:58:01 +02:00
Adrià 96e25f1fc1
Merge pull request #4567 from jagrat04/feat/libkernel-get-libkernel-text-location
feat(libkernel): implement sceKernelGetLibkernelTextLocation
2026-10-12 22:57:32 +02:00
Adrià 2fabe44c48
Merge pull request #3980 from MarcZX100/codex/carry-libkernel-setrlimit
feat(libkernel): export setrlimit
2026-10-12 22:57:08 +02:00
Adrià 955f4fbffe
Merge pull request #4207 from xXPBSXx/fix/ampr-amm-usage-stats
feat(libSceAmpr): answer sceAmprAmmGetUsageStatsData
2026-10-12 22:57:04 +02:00
David 62f6764cc2 feat(libkernel_sys): implement pathconf
Porpoise 2.7 (PPSA99764) stops at load on main 0f863c10:

    FAIL: unresolved ELF import oc98+zOImus from libkernel_sys.prx

oc98+zOImus is pathconf (tools/nid_names.py, aerolib.csv at
zecoxao/sce_symbols 2883963a). It is exported from libkernel_sys next to
link and readlink.

The lookup follows FreeBSD 11's kern_pathconf and namei (release/11.0.0,
671fb7df): links are followed, a path of 1024 bytes or more or a
component over 255 fails with ENAMETOOLONG, a missing path with ENOENT.
The values are the constants of FreeBSD 11's UFS ufs_pathconf, which
vop_stdpathconf shares where both answer. Names whose UFS value depends
on the mount, the kernel options or the page size, or on which UFS and
vop_stdpathconf disagree, throw; other names fail with EINVAL. The
console's filesystem values are unverified and recorded in
TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:56:28 +02:00
PrintOrb c35572ec18 fix(audioout): serialize shared SDL audio initialization 2026-10-12 15:54:46 -05:00
xXPBSXx d283d484a2 fix(libkernel): answer sceKernelGetPageTableStats
PPSA30601 (Resonance) stops at the throwing stub. The four int* arguments follow
OpenOrbis' libkernel.h, the Orbital type database and SharpProspero; the values
follow KytyPS5 (2048 entries of 2 MiB per side) without its accounting of used
entries, listed in TechnicalDebt.md. A null pointer returns EFAULT.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 22:54:27 +02:00
Mouad-Scriptz-0 09c985464c feat(libSceNpAuth): return the signed-out error from sceNpAuthGetAuthorizedAppCode
There is no PSN sign-in, so the code getter answers SCE_NP_ERROR_SIGNED_OUT
instead of throwing; its parameters are unknown and not read. Minecraft
(PPSA17221) calls it after its sign-in dialog and treats the result as
offline play. The request, token and wait calls are left to #3604.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:54:23 +02:00
Nesyth 83959f3153 test(agc): sample comp-to-single keys from write-watched memory that no import unwatches 2026-10-12 22:53:22 +02:00
Adrià 529f7bfd4a
Merge pull request #3848 from semirkabir/feat/usbd-libusb
feat(libSceUsbd): pass USB devices and transfers through to the host with libusb
2026-10-12 22:51:41 +02:00
Adrià c06fcc4ff3
Merge pull request #3764 from YossiYad/carry/libkernel-kqueue
feat(libkernel): implement kqueue, kevent and file events
2026-10-12 22:50:34 +02:00
Adrià c8debc7788
Merge pull request #4748 from jagrat04/feat/libkernel_sys-readlinkat
feat(libkernel_sys): implement readlinkat
2026-10-12 22:49:44 +02:00
DariusHQ 7250306b77 fix(libkernel): poll pipe descriptors
ProsperoTV (PPSA99003) stops after its menu opens because poll threw for
the read end of a pipe it polls next to its sockets. poll now reports pipe
readiness as FreeBSD's pipe_poll does: readable when data is buffered,
POLLHUP once the other end is closed, writable when PIPE_BUF bytes are
free. On Windows the pipe is checked with NtQueryInformationFile while the
sockets are waited on in 1 ms slices; on Linux the host poll waits on both.
A closed descriptor below the socket range reports POLLNVAL.
2026-10-12 23:49:25 +03:00
Semir Kabir 0634b443ef feat(libSceUlt): accept option parameters in sceUltQueueCreate and sceUltQueueDataResourcePoolCreate 2026-10-12 22:48:53 +02:00
Adrià 999c07a633
Merge pull request #3890 from MarcZX100/codex/carry-ampr-offset-bounds-3321
fix(ampr): reject command buffer offsets beyond bound memory
2026-10-12 22:48:32 +02:00
Adrià 03895fc51a
Merge pull request #3679 from MarcZX100/codex/ampr-cpp-error-3346
feat(libSceAmpr): implement std::_Throw_Cpp_error
2026-10-12 22:48:13 +02:00
Adrià Franch f89c7fb883 docs(libkernel): move the setrlimit debt line next to getrlimit
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 22:47:59 +02:00
MarcZX100 c049a4972c fix(libkernel): declare getrlimit before setrlimit 2026-10-12 22:47:55 +02:00
MarcZX100 01d201c346 feat(libkernel): export setrlimit 2026-10-12 22:47:55 +02:00
VitzS7 01874b4b25 fix(libkernel): mark pending signals under the pending lock
Before: MarkPending set the bit and notified while the waits checked the set
under pending.lock, so a signal raised between the check and the wait was lost
and sigwait, sigwaitinfo, a null-timeout sigtimedwait and pause hung forever.
Now: the bit is set while holding that lock, so a wait either sees it or is
notified after it has blocked. GuestSigtimedwait raises with no delay 500 times
without the first sleep the other senders use; on the previous code that hung in
2 of 10 runs, and it passes on the new one.
2026-10-12 17:47:34 -03:00
VitzS7 28063f1951 feat(libkernel): wait for pending guest signals in the signal waits
Before: raise, kill and pthread_kill delivered a signal at once or failed
with EINVAL, nothing stayed pending, and pause, sigwait, sigwaitinfo and
sigtimedwait called NotImplemented_nid_no_patch.

Now: a process-wide pending set holds signals 1 to 128. A signal raised
while it is blocked stays pending and is delivered when _sigprocmask
unblocks it, taken by sigwait, sigwaitinfo or sigtimedwait, or delivered by
pause, which runs its handler on the calling thread and returns -1 with
EINTR. pthread_kill to another thread leaves the signal pending for
whichever thread waits for it and answers ESRCH for a handle that is not a
live guest thread. sigtimedwait follows FreeBSD's sigtimedwait(2): EAGAIN
on timeout, EINVAL for a tv_nsec outside 0 to 1000000000 while nothing is
pending, and an indefinite wait with a null timeout.
2026-10-12 17:47:33 -03:00
Mouhand Kaddo 4f5f6d671c test(agc): ignore null shader modules in graphics mock
Pipeline libraries take ownership of shader modules during prebuild. Treat null handles as a no-op so moved-from modules do not decrement the live-object count twice.
2026-10-13 00:43:16 +04:00
Adrià c952c2b0ed
Merge pull request #4709 from fdfawef324/feat/agc-workloads
feat(agc): return null from the workload builders for unregistered streams
2026-10-12 22:41:39 +02:00
jagrat Singh 20243b81e4 feat(libkernel_sys): implement readlinkat 2026-10-13 02:09:59 +05:30
Adrià 84659e16d0
Merge pull request #4632 from AlxcBTW/feat/trace-gpu-track
feat(agc): add the GPU, GPU mutex waits and shader preparation to the trace
2026-10-12 22:39:23 +02:00
Adrià fa0cc752a6
Merge pull request #3604 from itsbo5/feat/libSceNpAuth-complete
feat(libSceNpAuth): implement offline auth requests
2026-10-12 22:38:22 +02:00
Adrià 532e041911
Merge pull request #4742 from yunusshaikh7/fix/trace-output-exit
fix(agc): stop the trace writer when the driver stops
2026-10-12 22:38:15 +02:00
Mouhand-Kaddo 9aeeea848f fix(agc): retain used descriptor sets in pipeline libraries 2026-10-13 00:38:10 +04:00
fdfawef324 f1b2e605e7 fix(shader): split a BDA span read's in-place loads from its fallback
On an RTX 3060 (Windows, driver 591.86) a dispatch never finishes when
the lanes of read_bda_span split between its in-place dword loads and
its per-dword byte fallback, which calls read_bda_dword_bytes: Windows
resets the GPU and the device is lost. The two were the arms of one
selection in the DontInline function. They are now two selections, the
loads under the span's condition and the fallback under its negation,
joined after both. Loads, lookups, faults and stops are unchanged for
every lane; only the SPIR-V control-flow shape changes (SPIR-V
specification 2.11, structured control flow). Every stage except mesh
shaders is emitted as SPIR-V 1.3, and OpSelect chooses between
composites with a scalar condition only from 1.4 on, so the join stays
a selection.

The same hang and fix were reported in #3291 on an RTX 4060 Laptop GPU
(Windows, driver 591.86) and an RTX 5060 (Linux, driver 590.48.01). An
RTX 4070 Laptop GPU on driver 616.92 does not hang with either shape.
The driver-side cause is unknown, so the shape is recorded in
docs/dev/debt/shader.md.

On main the hang fails nine tests on the RTX 3060, in two ways.
agc_driver_{flat,global}_loads{,_x2_x3,_x4} and
agc_driver_flat_apertures_{2,5} abort after 64 to 71 s: the lost batch
keeps its lease, so teardown waits 60 s for the pinned guest allocation.
agc_driver_pixel_interlock fails after about 4 to 7 s with
vkDeviceWaitIdle returning VK_ERROR_DEVICE_LOST (-4) and never reaches
the pin wait. All nine pass with the change.

Fixes #3291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:37:43 -04:00
Adrià Franch b7c67a3364 fix(libkernel): accept NOTE_EXTEND on a directory watch on Windows
FreeBSD's vfs_kqfilter checks neither the vnode type nor fflags, so the
registration is valid; it is only delivered for a move between directories,
which the Windows directory handle cannot tell from a removal plus an addition.
Also moves the TechnicalDebt entries to docs/dev/debt after main split the file.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 22:37:31 +02:00
Yossi Yadgar 28043ff928 test(libkernel): rename, unlink and rmdir entries of a watched directory 2026-10-12 22:37:08 +02:00
Yossi Yadgar 2aacb762dd test(libkernel): rename and delete a watched file through kqueue 2026-10-12 22:37:08 +02:00
David 2979da6808 feat(libkernel): implement file events
Cloudberry Kingdom (PPSA23827, #3177) registers its first kevent change
as a file watch: ident 3, EVFILT_VNODE, flags 0x25
(EV_ADD|EV_ENABLE|EV_CLEAR), fflags 0x37
(NOTE_DELETE|WRITE|EXTEND|LINK|RENAME). Palworld's Discord module
(PPSA23126, #2648) imports sceKernelAddFileEvent and
sceKernelDeleteFileEvent, which no library exported.

EVFILT_VNODE watches the host file or directory behind the descriptor
and turns host changes into FreeBSD 11 vnode hints, added whole when
they share a bit with the requested fflags as filt_vfsvnode does
(sys/kern/vfs_subr.c, release/11.0.1 34bd3475): a growing write is
NOTE_WRITE|NOTE_EXTEND, a shrinking truncate or an attribute change
NOTE_ATTRIB, a link count change NOTE_LINK or NOTE_DELETE, a pending
delete NOTE_DELETE, a new path NOTE_RENAME, and in a directory a new,
removed or renamed entry NOTE_WRITE (with NOTE_LINK for a subdirectory,
as vop_mkdir_post/vop_rmdir_post). Windows uses FindFirstChangeNotification
on the parent directory (and the watched directory) and compares handle
snapshots every 50 ms, since a write through an open handle is not
reported until it is flushed or closed (measured); Linux uses inotify.
Closing the descriptor, deleting the event or the queue stops the
watcher.

sceKernelAddFileEvent(eq, fd, watch, udata) and
sceKernelDeleteFileEvent(eq, fd) take the OpenOrbis 0a1aaf9d
(libkernel.h:35,109) and SharpProspero 5dfdb4b0 (KernelEqueue.cs:164,168)
signatures; NIDs cG3t15OK4Ow and UmXngHKB6is confirmed with
tools/nid_names.py. The watch bits are the fflags and the event is added
with EV_CLEAR, which is not confirmed on a title.

Throws: NOTE_REVOKE, NOTE_OPEN, NOTE_CLOSE, NOTE_CLOSE_WRITE, NOTE_READ
and unknown bits, NOTE_EXTEND on a directory on Windows (a move from
another directory cannot be told from a creation) and descriptors that
are not files, directories, pipes or sockets (pipes, sockets and kqueues
fail with EINVAL as in FreeBSD). Recorded in TechnicalDebt.

guest_kqueue adds a vnode watch that sees a write to a temporary file
with Cloudberry's flags, fflags filtering, a re-registration, the sce
pair on an equeue, EINVAL for sockets, pipes and the kqueue itself, the
close of a watched descriptor and a directory watch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:37:08 +02:00
David 9ef4aa2c40 feat(libkernel): implement kqueue and kevent over the event queue
Cloudberry Kingdom (PPSA23827, #3177) calls kqueue right after start-up
and stopped on the throwing declarations merged with #3337; Palworld's
Discord module (PPSA23126, #2648) imports kevent.

kqueue reserves a host null-device descriptor in the file descriptor
space and registers it as an event queue that reports each ready event
once per call and moves level-triggered ones behind the others, as
kqueue_scan does. close and sceKernelClose close the queue and drop the
descriptor's events from every queue, dup2 drops them for the target,
and dup/dup2 of a kqueue throw, so a reused descriptor number is never
read as a stale kqueue.

kevent follows FreeBSD 11 kern_event.c (release/11.0.1 34bd3475):
kqueue_kevent for the changelist (filter 0 skipped, EV_SYSFLAGS
cleared, EV_ERROR receipts with the errno in data, EV_RECEIPT, the
early return when nevents is exhausted), kqueue_register for EV_ADD,
EV_DELETE, EV_ENABLE, EBADF, ENOENT and EINVAL, kqueue_scan for the
timeout (EINVAL for a bad timespec, zero polls, above INT32_MAX waits
forever) and filt_timerattach, filt_usertouch for the timer and user
filters. Read and write events reuse the guest socket poll of
sceKernelAddReadEvent/WriteEvent.

Throws: other filters, EV_DISABLE, EV_DISPATCH, EV_FORCEONESHOT,
NOTE_LOWAT, EV_CLEAR on a socket, read/write events on non-socket
descriptors or another kqueue, changes to an existing timer (11.0 and
11.4 differ), a NOTE_NSECONDS fraction above one second and a negative
nevents. Recorded in TechnicalDebt.

Test guest_kqueue covers creation and close, timers, a user event
triggered from another thread, read and write events on a socket pair,
EV_ERROR receipts, the timeout and the error cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:36:59 +02:00
virp-mta 62d12756b7 feat(libSceNpAuth): complete offline request lifecycle following shadPS4 2026-10-12 22:34:51 +02:00
Dean 27873b0f74
Merge pull request #4407 from oneandonlydean/up4/fix-mspace-fragments
fix(libc): round mspace block sizes to the 32-byte alignment
2026-10-13 09:34:01 +13:00
Adrià 798855b567
Merge pull request #4666 from ErenYeager1836/feat/content-search-empty-library
feat(libSceContentSearch): implement the search calls over an empty library
2026-10-12 22:33:39 +02:00
Lexroid 257ff1e38f test(agc): a color view of several slices of a target with no array slices renders into its only slice
Marvel's Wolverine draws into a 256x256 mipmapped 2D target
(CB_COLOR_ATTRIB3 0x4dc6c000, no array slices) through CB_COLOR_VIEW
0x4046000: slices 0 to 35 at mip 1. The view's last slice is not bounded
by the surface on that path, so the draw renders into slice 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:32:49 +03:00
Lexroid 1d8749d00d fix(agc): render a color view of several array slices into its first slice
A CB_COLOR_VIEW whose SLICE_MAX is past SLICE_START was rejected. Without
a render target index export every primitive goes to SLICE_START, so the
target is that slice, as for a one-slice view. Layered draws into such a
view, and views of several 3D slices, still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:32:49 +03:00
Semir Kabir 42cf82953c test(libSceUsbd): require a non-null active config interface array 2026-10-12 22:32:42 +02:00
Semir Kabir 6cab297837 test(libSceUsbd): skip null interface altsettings in the interrupt endpoint scan 2026-10-12 22:32:42 +02:00
Semir Kabir faff4a6453 fix(libSceUsbd): cancel transfers under the state lock 2026-10-12 22:32:42 +02:00
Semir Kabir 98d594c9c1 feat(libSceUsbd): pass USB devices and transfers through to the host with libusb 2026-10-12 22:32:42 +02:00
Adrià 7cb200b82d
Merge pull request #4714 from p3n1cillin/claude/netctl-ap-dialog
feat(libSceNetCtlApDialog): run the offline access-point dialog lifecycle
2026-10-12 22:32:40 +02:00
Adrià 42496c5e57
Merge pull request #3865 from CnRJay/perf/agc-integer-dcc-clear
perf(agc): clear integer-format storage images with DCC code 0000 on the GPU
2026-10-12 22:28:17 +02:00
Yunus Shaikh 016b2dbe82 fix(agc): stop the trace writer when the driver stops
With APS5_TRACE_FRAMES or APS5_TRACE_SECONDS set, the trace output keeps
its writer in a static unique_ptr that is only destroyed at process
exit. On Windows its thread no longer runs by then, so the join in
~ProfileOutput never returns and the title does not exit once the trace
was written. Driver::stop now stops it next to the stderr writer, while
its thread still runs; the destructor at exit then has nothing to join.
2026-10-12 13:26:32 -07:00
Adrià 44ab0c39ee
Merge pull request #3886 from PrintOrb/fix/videoout-high-frame-rate
fix(videoout): support permitted high-frame-rate output for Quake II
2026-10-12 22:23:31 +02:00
fdfawef324 ef022d53b8 fix(agc): import GPU mappings on a host thread when the stack is short
The GPU-map observer imported a new mapping into Vulkan on the thread
that made the mapping, on whatever stack it ran. Guest fibers run on
contexts the title allocates in guest memory, with no guard page;
Demon's Souls packs its 16 KiB job fiber contexts back to back. A GPU
mapping made on a fiber used 10,616 bytes of the fiber's stack on
NVIDIA (Add, NoteGpuMapping, the registry walk in GuestAllocationsEnd,
the import, the fiber's entry and return), about 7.5 KiB of it for the
import, so a fiber that mapped GPU memory deep in a job could overrun
its context into the next one.

The observer now imports inline when the stack pointer lies inside the
thread's stack bounds with at least 256 KiB below it, and otherwise
starts a host thread for the import and joins it. On Windows the bounds
come from GetCurrentThreadStackLimits, which reads the TIB bounds that
libSceFiber sets to the fiber context while a fiber runs; on Linux from
pthread_getattr_np, whose bounds a fiber's stack lies outside of. A
mapping made while the thread holds the GPU mutex still imports inline:
a host thread could wait for that mutex forever. A host thread that
cannot be started is reported like any failed import, which is still
printed to stderr while the mapping carries on.

agc_driver_gpu_map_on_fiber maps GPU memory from a fiber with a 64 KiB
context and requires that the mapping use at most 8 KiB of it (10,616
bytes inline, 2,960 on a host thread) and start one host thread, then
maps the same memory from the main thread and requires that it start
none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:22:50 -04:00
Adrià Franch b3c8be5887 test(agc): run the integer storage clear check from ctest 2026-10-12 22:22:48 +02:00
Adrià Franch 09aa34d063 test(agc): pin the integer storage clear to DCC code 0000
StorageClearAvailable takes code 0000 on R8/R16/R32_UINT and refuses every
other code; drop the header comment that said integer formats were refused.
2026-10-12 22:22:48 +02:00
Chad 92b46a2b72 perf(agc): clear integer-format storage images with DCC code 0000 on the GPU
ClearColorFor refused every integer format, so a fast-cleared R32_UINT/R16_UINT/R8_UINT surface was uploaded through the CPU path: a guest read that waits for the GPU writers, then FillDccClear's zero texels. Code 0000 is zero bits in any format, so it maps to a zero integer clear. PPSA28416: ~1.4 s per 10 s of CPU uploads gone, 4.9 -> 5.3 fps.
2026-10-12 22:22:48 +02:00
Adrià 825620ae56
Merge pull request #3791 from YossiYad/carry/pragmata-small-exports
feat(exports): implement three small PRAGMATA exports
2026-10-12 22:22:19 +02:00
Adrià 621ce1da17
Merge pull request #3846 from tv7/fix/d16s8-depth-fallback
fix(agc): store D16 depth with stencil as D24 or D32 where the device lacks it
2026-10-12 22:20:05 +02:00
Adrià d5fcd087bd
Merge pull request #3821 from semirkabir/feat/coredump-attach-outside-handler
feat(libkernel): answer the coredump attach calls made outside the handler
2026-10-12 22:19:52 +02:00
Adrià 5382635cd0
Merge pull request #3800 from YossiYad/carry/libkernel-setitimer
feat(libkernel): add setitimer on the alarm timer
2026-10-12 22:19:39 +02:00
babyhuey c69eb7027d feat(libkernel): report hw.model from sysctl 2026-10-12 16:18:42 -04:00
Adrià 9ea71307a9
Merge pull request #3872 from LeandroLP23/fix/kernel-windows-directory-dup
fix(libkernel): share the directory state between duplicated descriptors on Windows
2026-10-12 22:18:02 +02:00
Adrià 16f993a534
Merge pull request #3787 from YossiYad/carry/libkernel-jit-shared-memory
feat(libkernel): implement the JIT shared memory calls
2026-10-12 22:17:55 +02:00
Adrià 9f8a1080aa
Merge pull request #3728 from MarcZX100/codex/net-resolver-abort-3153
feat(libSceNet): implement resolver abort and multiple records
2026-10-12 22:17:43 +02:00
AlxcBTW eb8a7255d2 feat(agc): add the GPU, GPU mutex waits and shader preparation to the trace
The trace gets a gpu track: one slice per recorder batch from its timestamp
pair, and with APS5_PROFILE_GPU=1 one per command class range under the
[gputime] class names. The GPU clock is mapped onto the CPU clock from
calibrated timestamps (VK_KHR_calibrated_timestamps or the EXT version,
enabled only when a trace switch is set) taken when the window opens and
when it closes. A traced thread's wait for the GPU mutex becomes a
GpuMutex.wait.<site> slice, and the shader preparation threads are traced
with smaller buffers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:13:44 +02:00
Adrià 0428328b79
Merge pull request #4581 from AlxcBTW/feat/trace-digest
feat(tools): digest a performance trace for an issue or a pull request
2026-10-12 22:13:37 +02:00
Adrià Franch 9387da4fa2 style(agc): drop the duplicated DepthSurface.hpp include in Pipeline.cpp 2026-10-12 22:13:27 +02:00
Lexroid 522c7424a8 fix(agc): check sample location depth support on the host depth format
The depth image is created with the host format, so the sample locations
check for the image and for the pipeline asks about that format too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:13:24 +02:00
Adrià Franch 2115dac9a9 docs(debt): record the D16 stencil depth host format fallback
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 22:13:24 +02:00
Lexroid 7d34a6aa8b fix(agc): store D16 depth with stencil as D24 or D32 where the device lacks it
A 16-bit depth target with stencil maps to VK_FORMAT_D16_UNORM_S8_UINT,
which NVIDIA devices do not support as an attachment, so creating it threw.
The surface, its views and the pipelines now use the first of D16_UNORM_S8_UINT,
D24_UNORM_S8_UINT and D32_SFLOAT_S8_UINT the device can attach and sample.
Guest-side choices (16-bit sampled views, bias units) still follow the guest
format. A constant depth bias is scaled by 256 for D24 storage; on D32 float
storage it throws, as its unit depends on the depth value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:13:24 +02:00
Adrià 198e022107
Merge pull request #3781 from YossiYad/carry/libkernel-termios-calls
feat(libkernel): implement the remaining termios calls
2026-10-12 22:12:13 +02:00
Adrià 52c9b65480
Merge pull request #3849 from LeandroLP23/docs/debt-windows-gui-console
docs(debt): update the console and random device entries to current main
2026-10-12 22:11:28 +02:00
David dbbd6d582c fix(libc): append through a descriptor opened by fdopen in an append mode on Windows 2026-10-12 20:09:54 +00:00
Yossi Yadgar 5e1ffc29ae fix(libkernel): report the setitimer interval from getitimer
getitimer on main predates setitimer and always reported a zero it_interval, so a periodic ITIMER_REAL armed by setitimer read back as one-shot.
2026-10-12 22:08:23 +02:00
screamm 5471844c5d feat(libkernel): add setitimer on the alarm timer
PS5MC (PPSA99420) imports setitimer (hPWDGx8ioXQ, aerolib) at registry
index 472, after tcsetpgrp and before getitimer. Predicted stop:
"FAIL: unresolved ELF import hPWDGx8ioXQ from libkernel.prx".

setitimer follows FreeBSD 11.4 kern_time.c (8c639945) sys_setitimer and
kern_setitimer: EINVAL for an unknown timer and for an itimerfix failure
or more than INT32_MAX / 2 seconds; a zero value clears the interval and
disarms; a null value reads the timer, EFAULT when the output is null too.
ITIMER_REAL shares the alarm state, now with an interval that re-arms it
as realitexpire does; alarm clears it, as FreeBSD's alarm.c does.

Guest SIGALRM handlers are not run, so an expiry with a handler, or with
SIGALRM blocked (signals are never left pending), throws naming the
interval; SIG_IGN drops it and the default disposition exits with 142,
as alarm already did. Intervals below 1 ms throw (itimerfix rounds them
to tick / 16 and the console's hz is unknown). ITIMER_VIRTUAL and
ITIMER_PROF throw when armed and read and disarm as zero.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:08:23 +02:00
Adrià 0142215687
Merge pull request #3720 from MarcZX100/codex/share-clip-extended-3333
feat(libSceShare): implement extended video clip capture
2026-10-12 22:07:24 +02:00
Adrià Franch 5b73ecb385 docs(technical-debt): cite shadPS4 for the coredump error value and move the line away from adjacent PRs
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 22:04:17 +02:00
dantdmdarealguy 90f00d4d24 feat(libkernel): answer the coredump attach calls made outside the handler
sceCoredumpAttachMemoryRegion and sceCoredumpAttachUserMemoryFile take
(uint32_t userValue, const void* mem, size_t size): the Orbital IDA type
database and the SharpProspero bindings agree on the first, the second
has only SharpProspero. Attaching belongs inside the core dump handler
the system runs after the process stops; a call from anywhere else gets
SCE_COREDUMP_ERROR_NOT_IN_COREDUMP_HANDLER. The handler is never invoked
here, so every call returns that error and nothing is recorded. Whether
the console checks the region before the calling context is unknown, so
a null, empty or wrapping region throws.

The error value 0x81180003 is inferred from fpPS4's 0x81180001 and
0x81180002 and the numbering of the Vita's SceCoredump error table;
TechnicalDebt records the sources and what remains unverified.

guest_coredump_attach: the error before, during and after a handler
registration, from another thread too, without running the handler or
touching the region; null, empty and wrapping regions throw naming the
function.
2026-10-12 22:04:17 +02:00
Adrià Franch 833cc357da docs(debt): remove the duplicated fused PPSA23566 line
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 22:04:02 +02:00
Adrià Franch 8f1077a29c docs(debt): drop sceNetResolverAbort from the unknown-signature line
The PR added a second PPSA23566 line fused with the PPSA28416 one instead of editing the original.
2026-10-12 22:03:56 +02:00
David 3d64981643 feat(libSceNet): implement sceNetResolverAbort and sceNetResolverStartNtoaMultipleRecords
UFC 6 (PPSA23566) imports sceNetResolverAbort (#992, #1502); Palworld
(PPSA23126) and LEGO Horizon Adventures (PPSA14632) import
sceNetResolverStartNtoaMultipleRecords.

Signatures and behaviour follow shadPS4 811bfcd7d17e
(src/core/libraries/net/net.cpp, net_resolver.cpp); the abort signature
also matches SharpProspero Interop/Net/Socket.cs.

sceNetResolverStartNtoaMultipleRecords shares the lookup of the Ex form
and, like it, throws for any flag. sceNetResolverAbort returns EBADF for
an unknown resolver and throws for flag bits other than NTOA (1) and
ATON (2) preservation. Host lookups cannot be interrupted, so an abort
during a running lookup makes it fail with EINTR when the host call
returns, without writing its output; with nothing running, the
preservation flags make the next lookup of that kind fail with EINTR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit bcc8be8a58aa6a9e6b7c288d8a90af6ed63837aa)
2026-10-12 22:03:56 +02:00
Adrià 9742ec12c8
Merge pull request #3694 from MarcZX100/codex/libc-getopt-3562
feat(libSceLibcInternal): implement getopt and getopt_long
2026-10-12 22:03:44 +02:00
Adrià 70da6f41c3
Merge pull request #3718 from MarcZX100/codex/libsce-np-ea-access-3339
feat(libSceNpPartner001): implement EA access init and terminate
2026-10-12 22:03:30 +02:00
screamm 3b7ac1596d fix(libkernel): create the JIT shared memory backing in one call
Review of #3787 asked for no retries after an error in Jit.cpp.

Linux: memfd_create is called once with MFD_CLOEXEC. MFD_EXEC was
tried first and dropped on EINVAL; the flag only sets the file's execute
permission bits (Linux 6.3 and later), not whether the object maps
PROT_EXEC, which is decided by the mapping protection, as for the direct
memory memfd in DirectMemory.cpp. A one-shot choice from the headers
would fail on older kernels, so the flag is dropped; TechnicalDebt
records it.

Windows: the delete-on-close backing file is named from the process id,
a process-wide atomic counter and the performance counter, so CREATE_NEW
cannot meet an existing name, and any CreateFileW failure throws with
the Win32 error instead of looping up to 64 times on ERROR_FILE_EXISTS.
The descriptor stays a CRT descriptor on the file, so close, dup and
dup2 keep working as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:59:19 +02:00
Yossi Yadgar 7c473fa398 test(libkernel): keep JIT shared memory descriptors in step across dup2 2026-10-12 21:59:19 +02:00
screamm 7d3dd554da feat(libkernel): implement the JIT shared memory calls
The three JIT shared memory exports (avvJ3J0H0EY, MR221Mwo0Pc,
YKT49TOLQWs) are absent imports of three homebrew titles that cannot
finish loading without them. Predicted next stops (registry order):

- VLC PPSA85300 after getdtablesize (idx 354):
  "FAIL: unresolved ELF import YKT49TOLQWs from libkernel.prx"
  (Map idx 452, Create idx 462)
- XPSemu PPSA97358 after tcsendbreak (idx 214):
  "FAIL: unresolved ELF import avvJ3J0H0EY from libkernel.prx"
  (Create idx 398, Map idx 399)
- RetroArch PPSA99169:
  "FAIL: unresolved ELF import avvJ3J0H0EY from libkernel.prx"
  (Create 476, Alias 477, Map 478)

XPSemu and VLC (ps5/compat/mmap.c, __wrap_mmap) create an object for
every anonymous PROT_EXEC mapping (QEMU's TCG buffer) and map it with
the same protection, falling back to flexible memory on any non-zero
return. RetroArch's eboot runs a probe: Create("ps5-platform-probe",
0x10000, 7, &fd), Alias(fd, 3, &alias), Map(fd, 5, &address), then logs
"jit create=0x%08x alias=0x%08x map=0x%08x".

Signatures from Orbital cc408367 tools/ida/db_types.json (name, len,
maxProt, fdOut; fd, maxProt, fdOut; fd, prot, startOut), matching
ps4sdk 4df9d001 include/sce/kernel.h, ps5-jar-loader 8034177e
LibKernel.java and the three titles' call sites. SharpProspero 5dfdb4b0
declares the alias as returning the descriptor; the RetroArch call site
passes an out pointer.

The object is a host anonymous file (memfd on Linux, a delete-on-close
temporary file mapped as a PAGE_EXECUTE_READWRITE section on Windows),
the alias a duplicate descriptor, and each map maps the whole object
through the direct memory placement path, so a write through one view
is visible through the others. Bad lengths and protection bits are
EINVAL, protection past the descriptor's maximum is EACCES (FreeBSD 11
vm_map_protect), unknown descriptors are EBADF; close, dup and dup2
keep the descriptor table in step. Unverified details are recorded in
TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:59:19 +02:00
screamm 96988048ad feat(libSceSharePlay): implement sceSharePlayProhibitController
PRAGMATA (PPSA02530) imports sceSharePlayProhibitController (NID
FzQS6DREDfk), which no library exports on main, so the load fails on the
unresolved import. It is one of the "six declared-only imports" of
xXPBSXx's branch in #3043 (comment 6107100345): "These only stop the
load failure; as described above, the title calls some of them later and
needs their real behavior."

sharpemu src/SharpEmu.Libs/Share/SharePlayExports.cs:9-31
(a2983692930564815a77f81e74c151268f5b935f, used as a source of facts)
takes one value, accepts 0 and 1 and returns 0. Nothing here would read
the setting, as no Share Play session or visitor controller exists, so
it is not stored. sharpemu rejects other values with its synthetic
0x80020003, not a Share Play code, so they throw, as
sceSharePlayInitialize does for its unknown error. Like the other exports
of the library it does not check initialization. The NID hashes from the
name and is in aerolib. Unverified points are in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:58:43 +02:00
screamm 4ab6a047f6 feat(libSceRazorCpu): implement sceRazorCpuSync
PRAGMATA (PPSA02530) imports sceRazorCpuSync (NID Ax7NjOzctIM), which no
library exports on main, so the load fails on the unresolved import. The
title calls it after sceConvertKeycodeGetCharacter. From #3043 (comment
6106731532): "`sceRazorCpuSync`: answering 0 and doing nothing was
enough to carry on (the other `sceRazorCpu*` calls in `main` are no-ops
without a capture)."

SharpProspero src/SharpProspero/Interop/Debug/RazorCpu.cs:119-122
(5dfdb4b0b166e83dc9ae275001afb695f12c7174, GPL-3.0, used as a source of
facts) gives int sceRazorCpuSync(void), an unnamed frame-boundary event.
Without a capture there is no event to record, so it returns 0 and does
nothing, like the other sceRazorCpu markers here and the shadPS4 stub
(razor_cpu.cpp:143, 3a9f57265d28975658f1ca941daa5c879c7a74bd). The NID
hashes from the name and is in aerolib. Unverified points are in
TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:58:39 +02:00
screamm 5690b84a49 feat(libSceNpEntitlementAccess): implement sceNpEntitlementAccessGetGameTrialsFlag
PRAGMATA (PPSA02530) calls it after sceRazorCpuSync and stops on main
with "sceNpEntitlementAccessGetGameTrialsFlag not implemented". From
called once; I logged four register values but cannot tell which are
arguments. Answering 0 without writing anything carried on." Killing
Floor 3 (PPSA08427) and RE4 also import it.

The title is reported as a full game, not a game trial: 0 is written to
the uint32_t output and 0 returned; a null pointer returns 0x817D0002.
Signature, value, one-word write and error follow sharpemu
src/SharpEmu.Libs/Np/NpEntitlementAccessExports.cs:98-116 and its test
NpEntitlementAccessExportsTests.cs:16-36 (a2983692930564815a77f81e74c151268f5b935f),
used as a source of facts; 0x817D0002 is also the parameter error of
KytyPS5, prosper and sceNpEntitlementAccessGetEntitlementKey here. The
library has no initialization state, so none is checked. The NID
y7JD1gfwyfA hashes from the name and is in aerolib. Unverified points
are in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:58:36 +02:00
Yunus Shaikh 8371431ef1 build: add Tracy with the other third-party projects
The include sat next to add_subdirectory(core/libs), which other open pull requests rewrite. Tracy is now added after FFmpeg, still at the top-level scope, so the client is built with the same flags.
2026-10-12 12:55:40 -07:00
Yunus Shaikh 28ca53dc89 feat(agc): report performance timer scopes to Tracy with APS5_ENABLE_TRACY
APS5_ENABLE_TRACY=ON builds the Tracy 0.14.1 client from the new
3rdparty/tracy submodule as a shared library next to the patched
libraries. Every PerformanceTimer scope of libSceAgcDriver and
libSceVideoOut becomes a Tracy zone, each presented flip ends a frame,
and the queue workers and the presenter name their threads. The client
listens only on localhost and records only while a profiler is
connected; sampling, system tracing, call stacks, code transfer and its
crash handler are off. Without the option nothing of Tracy is compiled.

On MinGW the client is built without thread_local destructors and with
TRACY_DELAYED_INIT, because emulated TLS frees thread_local objects
before their destructors run; a thread's event producer then stays
alive until the process exits instead of being destroyed on freed
memory.
2026-10-12 12:55:40 -07:00
xXPBSXx badb94cc78 docs(debt): list the PPSA02530 imports in debt/libSceAcm.md
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:51:37 +02:00
xXPBSXx 5377f0fe04 fix(exports): leave sceRazorCpuSync and sceSharePlayProhibitController to #3791
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:51:37 +02:00
xXPBSXx 147c0db150 fix(exports): export the calls PPSA02530 imports
PPSA02530 (PRAGMATA) fails to load without these imports that no library exports. Their signatures are unknown, so they are declared without parameters and throw until they are implemented. Adds a TechnicalDebt entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:51:36 +02:00
Adrià 3e0e01f35f
Merge pull request #4526 from AlxcBTW/feat/trace-capture
feat(agc): record a present window as a Chrome trace and a summary line
2026-10-12 21:49:54 +02:00
Yossi Yadgar 0c1fa50e8e test(libkernel): termios calls on a Unix socket and a directory descriptor 2026-10-12 21:48:20 +02:00
screamm 51b3e3ef38 feat(libkernel): implement the remaining termios calls
Adds tcsendbreak (vXE-dIUIZlE), tcdrain (brGGJWsZauw), tcflush
(FxHW5NuEXsY), tcflow (OG8xRaGIpqk), tcgetpgrp (5OEl1mRhUm0) and
tcsetpgrp (YMuesZTyTl4) next to tcgetattr and tcsetattr in
File/src/Terminal.cpp. The NIDs come from tools/nid_names.py and match
aerolib.csv (zecoxao/sce_symbols 2883963a).

They follow FreeBSD 11.4 lib/libc/gen/termios.c (8c639945), which
implements each one over a terminal ioctl: tcflush returns EINVAL for a
queue other than TCIFLUSH, TCOFLUSH or TCIOFLUSH and tcflow for an
action outside TCOOFF..TCION before the descriptor is used; every other
call fails with the error the merged tcgetattr gives (EBADF for a closed
descriptor, ENOTTY for a file or pipe, EADDRNOTAVAIL or EOPNOTSUPP for a
socket, per soo_ioctl and in_control/in6_control). tcsendbreak fails on
TIOCSBRK before its 0.4 s pause, and tcflow's TCIOFF/TCION fail in
tcgetattr. FreeBSD's pipe_ioctl answers TIOCGPGRP/TIOCSPGRP on a pipe or
FIFO with the SIGIO owner, which is not modelled, so tcgetpgrp and
tcsetpgrp throw on a host pipe above descriptor 2.

Titles (homebrew catalog #1578), predicted stops from registry order:
- PS5MC PPSA99420 imports tcsendbreak (442), tcdrain (443), tcflush
  (444), tcflow (445), tcgetpgrp (462) and tcsetpgrp (463); once pause
  and setrlimit are in, it stops at
  "FAIL: unresolved ELF import vXE-dIUIZlE from libkernel.prx".
- XPSemu PPSA97358 imports tcsendbreak (214), its first uncovered import
  after execv, sigwait, setrlimit, mlockall, setuid and getopt:
  "FAIL: unresolved ELF import vXE-dIUIZlE from libkernel.prx".

guest_terminal covers each call over stdin, stdout, stderr, a file, both
pipe ends and an AF_INET socket, the EINVAL cases (also on -1), and
EBADF for -1, a closed socket, a closed pipe and a closed file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 21:48:20 +02:00
Gjon Gojcevic 0b7de0e737 feat(shader): read hull inputs at a control-point index computed from data
A hull program may read its input control points from LDS at an index it
computes from data, such as an index loaded from memory or min(invocation, n).
The tessellation lowering refused such a read because its address is not
affine in the invocation and relative patch.

The address evaluator now carries a dynamic term for a hull LDS read: a value
that is not affine but does not depend on the relative patch index, with the
multiple it is scaled by. Terms of the same value add up ((t << 1) + t of
t = index << 3 is 24 * index); terms of different values keep the greatest
common divisor of their multiples. The read is lowered from the program's own
address arithmetic, and the relative index may reach it only with the stride
of a patch's inputs. A computed offset that is not a whole number of control
points is refused.

The SPIR-V emitter clamps a hull input control-point index to the patch's last
input, recorded as technical debt: on the console an index past the patch
reads LDS of a neighbouring patch.
2026-10-12 15:47:59 -04:00
Zayd Zaari 396412496f fix(rtc): reject date strings ending at the minutes
Require the measured separator after RFC date minutes when seconds are absent. Preserve the destination tick on the parse failure and retain the accepted trailing-space and seconds controls.

AI-assisted; based on guarded PS5 measurements with controlled input backing storage.
2026-10-12 19:44:03 +00:00
Adrià Franch 6116fc75e1 docs(agc): say the last present of a trace window has no folded sample
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 21:42:59 +02:00
AlxcBTW af52bc430f style(agc): restore the space before QueryBdaByteFeatures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:42:59 +02:00
AlxcBTW 5c7da226df fix(agc): write the trace's gzip framing around a raw deflate stream
The zlib in the tree (libjpeg-turbo's) is built with NO_GZIP, so
deflateInit2 refuses the gzip wrapper (windowBits 31) and no trace was
written. The trace file now writes the gzip header, a raw deflate stream,
and the CRC-32 and size trailer itself. The writer's result line is flushed,
since stderr is buffered in a title process. The file writing moves to
TraceFile, and a test inflates a written file and checks its CRC-32 and
size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:42:59 +02:00
AlxcBTW 5668e0d0e7 feat(agc): record a present window as a Chrome trace and a summary line
APS5_TRACE_FRAMES=<start>:<count> (or APS5_TRACE_SECONDS=<start>:<length>)
records every PerformanceTimer scope and stage of the queue workers and the
presenter inside the window as complete events, named after their frame
timing keys, into a preallocated buffer per thread. Slices under 20 us are
counted per thread instead of written; a full buffer stops that thread and
sets trace_dropped. When the window closes, a ProfileOutput writer thread
writes aps5-trace-<commit>-<pid>.json.gz and appends one line to
aps5-summary.jsonl. Without either switch a PerformanceTimer costs one more
predictable branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:42:59 +02:00
Adrià cf4557e5d8
Merge pull request #4570 from AlxcBTW/feat/sampler-collapsed
feat(agc): write the worker sampler's stacks as collapsed stacks
2026-10-12 21:42:52 +02:00
Adrià 8027c749e5
Merge pull request #4707 from adriadam10/feat/progress-history
feat(progress): publish a progress history chart
2026-10-12 21:40:14 +02:00
Romans Pokrovskis b6f1a4a69d test(agc): verify display XOR array attachment transport
Run the existing array-layer draw, recompiled shader load, untouched-layer and guest-publication checks with D_X as well as R_X. This exercises the resident array path that carries slice-dependent address XOR; a direct per-slice copy is not an equivalent model.

AI-assisted implementation and validation: Codex.
2026-10-12 22:38:59 +03:00
Romans Pokrovskis 4326c7c212 fix(agc): validate display XOR bits before resident lookup
Apply the source-configured D_X XOR refusal during color decoding as well as direct layout construction. Regression tests reject each raw column-bit combination before storage or rendering is selected. Existing resident-array and packed-mip refusal paths remain in force.

AI-assisted implementation and validation: Codex.
2026-10-12 22:38:59 +03:00
Romans Pokrovskis f27bdf4d73 feat(agc): support 64 KiB display XOR color targets
Map SW_64KB_D_X color surfaces through the existing source-backed texture equations and mip geometry. Keep display and render-target equation caches separate. Reject unresolved raw column bits for the new mode instead of accepting them.

Cover the captured PPSA99902 descriptor, independent source offsets, pipe/bank tags, transfers, array/mip placement and resident/non-resident GPU draws. Record unmeasured console behavior in TechnicalDebt.

CPU validation on main e013f8c9: captured-descriptor failure 5/5; changed passes 5/5; pinned AMD addrlib reference 536940 addresses per run, five runs. Full build and GPU validation are tracked externally. AI-assisted implementation and validation: Codex.
2026-10-12 22:38:59 +03:00
Ondra97 85cf9c3ac7 fix(tools): preserve technical debt section moves 2026-10-12 21:37:58 +02:00
babyhuey db3726a868 feat(libkernel): export sceKernelMmap 2026-10-12 15:34:17 -04:00
milescoviello b8d71fc7f2 fix(libkernel): dissolve a UDP association on connect to AF_UNSPEC
connect() on a guest datagram socket checked the address family before
doing anything, so an AF_UNSPEC (null) address failed with EAFNOSUPPORT
and left the socket connected: getpeername() still reported the old
peer, send() without an address still went there, and datagrams from
any other sender were dropped by the host.

FreeBSD 11.4 disconnects a connected datagram socket first and only then
rejects the address. sys/kern/uipc_socket.c, soconnectat():

	 * If protocol is connection-based, can only connect once.
	 * Otherwise, if connected, try to disconnect first.  This allows
	 * user to disconnect by connecting to, e.g., a null address.
	 */
	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
	    (error = sodisconnect(so)))) {

udp_disconnect() (sys/netinet/udp_usrreq.c) clears the peer and resets
only the local address, keeping the local port:

	in_pcbdisconnect(inp);
	inp->inp_laddr.s_addr = INADDR_ANY;

after which in_pcbconnect_setup() (sys/netinet/in_pcb.c) returns
EAFNOSUPPORT for the full-size address, as main already does. connect(2)
documents it: "Datagram sockets may dissolve the association by
connecting to an invalid address, such as a null address."

A connected internet datagram socket given an address whose family byte
is 0 is now disconnected on the host first (AF_UNSPEC on Linux, a zeroed
address on Windows) and the call then fails as before. Linux also drops
an ephemeral local port on that disconnect, so the port is bound again
on the wildcard address, which is what FreeBSD leaves. A host
failure during the disconnect is returned as the call's error. Stream
sockets keep the previous path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:33:20 +00:00
AlxcBTW ca219d1b67 feat(tools): digest a performance trace for an issue or a pull request
tools/trace_digest.py reads an APS5_TRACE_FRAMES capture (aps5-trace-*.json.gz)
and prints a markdown report of a few KB, or the same data as JSON: the
summary line from aps5-summary.jsonl, the slowest frames with their largest
slices, the busy, wait and untraced time of each thread, the largest slices
per frame, the longest waits, and with --stacks the hottest frames of an
APS5_SAMPLE_WORKER collapsed-stack file. Python standard library only; a
unittest checks every section on a small synthetic trace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:33:18 +02:00
PrintOrb b6ae7da1ed docs(videoout): preserve split debt layout after merging main 2026-10-12 14:32:58 -05:00
Jordan Hans bdb0be019e feat(libSceAgcDriver): export sceAgcDriverGetHsOffchipParam 2026-10-12 19:32:46 +00:00
xXPBSXx 0485570577 fix(exports): export the calls PPSA29866 imports
PPSA29866 (Tomba! 2) fails to load without these imports that no library exports. Their signatures are unknown, so they are declared without parameters and throw until they are implemented. Adds a TechnicalDebt entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:32:38 +02:00
Adrià Franch 63e60db1a7 feat(progress): publish a progress history chart
tools/progress_history.py measures the first-parent history of main with
the rules of tools/progress.py, one point per day, and writes history.json,
history.svg and history.html. The Progress workflow runs it after
progress.py; the README shows the chart under the map and links the page.
Labels and points compact as days accumulate.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 21:31:09 +02:00
Dean 2f4cc8983b
Merge pull request #4431 from AlxcBTW/refactor/spirv-specializer-debris
refactor(shader): drop unused folded constants and unreachable blocks after specialization
2026-10-13 08:30:39 +13:00
PrintOrb 8024471225
Merge branch 'main' into fix/videoout-high-frame-rate 2026-10-12 14:27:28 -05:00
David-cmrg bed1b15096 fix(libkernel): create /data at start-up 2026-10-12 21:27:00 +02:00
Felipe Arce f3b8ef7abf feat(libSceLibcInternal): implement fdopendir 2026-10-12 16:23:42 -03:00
AlxcBTW 428963d3b3 feat(agc): write the worker sampler's stacks as collapsed stacks
APS5_SAMPLE_WORKER=<file> now also writes <file stem>.collapsed.txt: one
"frame;...;frame count" line per distinct stack of queue worker 0, root
first, frames as module+0xRVA, which speedscope.app and flamegraph.pl
open. Walks go up to 64 frames, and nothing allocates while the worker is
suspended.

The libraries are built with -fno-asynchronous-unwind-tables, so most of
their functions have no .pdata entry, only a DWARF record in .ehfram, and a
walk ended at the first such frame. The worker's walk now steps those
frames through their record, with the CIE/FDE decoding and the call frame
instructions of libc's unwinder, which move from Unwind.cpp into its
header unchanged. A module is indexed after the worker resumes, the first
time a walk meets it, and every register the step restores is read inside
the worker's stack. The process sampler (APS5_SAMPLE_THREADS) keeps its 12
frames through .pdata.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:23:11 +02:00
fdfawef324 f8257a112b feat(agc): return null from the workload builders for unregistered streams
sceAgcDcbSetWorkloadStreamInactive and the three ACB workload builders
(sceAgcAcbSetWorkloadsActive, sceAgcAcbSetWorkloadComplete,
sceAgcAcbSetWorkloadStreamInactive) threw for every call, and
sceAgcDcbSetWorkloadsActive read the workload ids before it checked the
stream.

The prosper console oracle (mattias800/prosper df074498,
prosper/tests/data/console_oracle/agcbuild.golden.tsv lines 48-56 and
196-204) measured all six calls on a PS5 with three argument patterns
and no workload stream registered: each returned null and wrote nothing.
Pattern b passes stream 1 with the workload ids at address 2, so the
console checks the stream before it reads the ids; here that call read
address 2 and crashed.

The four builders now return null for a null command buffer or a stream
that is not registered, and still throw for a registered stream: the
packet a registered stream gets is not measured, KytyPS5 has no body for
them, and its IT_NOP layout for the DCB calls differs from the
SET_UCONFIG_REG, WRITE_DATA and SET_WORKLOAD sequence OpenAGC
(3c7e8072, src/agc_workload_packet.c) derives from the driver. The
signatures are OpenAGC's DCB ones (src/game_compat.c), which says the
ACB calls use the same driver builders. sceAgcDcbSetWorkloadsActive now
checks the stream before the ids, as OpenAGC does. Recorded in
docs/dev/debt/libSceAgc.md.

agc_commands gains testWorkloadStreams: the three measured patterns for
all six calls (null, buffer untouched), an exhausted and a null buffer,
and a registered stream that throws without touching the buffer. On
upstream/main it fails with "sceAgcDcbSetWorkloadStreamInactive not
implemented", and the DCB active pattern b alone segfaults reading
0x2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:22:21 -04:00
Hannah Lyons 057a7317d1 feat(libc): implement expm1f, erff, lgamma and llroundl 2026-10-12 15:19:24 -04:00
Karan Vora 1dc99ba0a2 perf(shader): drop the input flush that rcp, rsq, sqrt, exp and log results never use
The SPIR-V emitters of FPRecip32, FPRecipSqrt32, FPSqrt, FPExp2 and FPLog2
flushed a denormal input to its signed zero before the host operation.
Since #537, unaryFloatSpecials replaces the host result for every input
below 2^-126 with the hardware's result for a zero of the same sign: rcp
and rsq give a signed infinity, sqrt the signed zero, log -inf and exp 1.0.
floatUnary and float16Unary both go through it, so the flushed input could
only change a value that is then discarded. v_rcp_iflag_f32 gets the same
special values and already went without the flush.

The pixel prologue computes PositionW as FPRecip32 of FragCoord.w without
those special values, so it now flushes FragCoord.w in the IR first and
gives the same result as before.
2026-10-12 15:17:41 -04:00
xXPBSXx 8f254e0623 docs(debt): move the resource tracker entries to debt/shader.md
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:18 +02:00
xXPBSXx 7d508cf779 fix(recompiler): evaluate pruning conditions without throwing on null roots
A branch condition that reads through a null user-data pointer is now
treated as not evaluable instead of being caught, so every successor
stays active.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:18 +02:00
xXPBSXx 37003b7a38 fix(recompiler): track which branch uses each image, not only each descriptor source
Several image instructions of different dimensions on the same T# address share
one descriptor source, so a source stays active as soon as one of them is taken
and the others are still checked against the T#. Record the images a block uses
as well, deactivate the images used only behind a branch the capture does not
take, and bind them as null descriptors.

PPSA15246 (Teardown) then passes the "incompatible with the static runtime
image interface" check of the three image_store variants that are not taken.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:18 +02:00
xXPBSXx 0accdb487e style(recompiler): drop the comment above the resource control flow planner
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:18 +02:00
xXPBSXx 7b9c7ca582 fix(recompiler): leave out descriptor sources behind a branch the capture decides
A compute kernel that picks a buffer or an image path from an SRT word reads
the same address as a V# in one path and as a T# in another. The resource
tracker now records which block uses each descriptor source and builds the
resource control flow from the structured block terminators, so a source whose
only uses sit behind a conditional branch with a clean, evaluable condition is
left inactive (bound as zero words, not validated) when the capture takes the
other path. A condition that reads inaccessible memory is not evaluable instead
of throwing.

PPSA15246 (Teardown) stopped on "runtime image descriptor is invalid" for the
untaken path of such a kernel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:18 +02:00
xXPBSXx 4b6f463751 feat(libSceAmpr): answer sceAmprAmmGetUsageStatsData
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 21:14:14 +02:00
Adrià 682ef0c174
Merge pull request #4444 from fma-rc/docs/discussion-form-game-bring-up
docs: add a discussion form for game bring-up threads
2026-10-12 21:11:46 +02:00
Adrià Franch 908cd42880 docs: point the bring-up form to the blocker map
COMPATIBILITY.md no longer exists
2026-10-12 21:11:37 +02:00
Nesyth 2fb6dccd75 fix(agc): read comp-to-single DCC keys of sampled textures and storage images 2026-10-12 21:08:08 +02:00
Nesyth 78f8df053f perf(libc): share one snapshot of the registered guest ranges between leases until the registry changes 2026-10-12 21:07:13 +02:00
Dean Galvin 1d3f642760 fix(agc): report the test's page protection change to the page cache
The second import-window case of agc_write_tracking makes one page
unreadable with VirtualProtect or mprotect and expects an import that
stays watched to throw before it copies its range. On Windows CheckRange
answers from its table of committed arena pages, which is kept current
by the registry's invalidator. The first case had checked the same
allocation, so the table still said the page was readable, the check
passed and the copy faulted on the page.

ProtectPage now reports the change through GuestAllocationsInvalidate,
as the registry does for a guest protection change and as
tests/BdaResources.cpp does after VirtualProtect.
2026-10-13 08:04:52 +13:00
Dean Galvin 406c72d9be perf(agc): compare an import window's pages when the window closes
A host import that leaves its range watched can resolve the write
protection of the imported pages without storing anything, as NVIDIA's
Linux driver does for every page. ImportWatched stamped those pages as a
possible CPU store (BlockMaybeWritten), and only a storage image tracked
by 64 KiB unit could clear the stamp, by comparing with a copy of the
guest bytes it was uploaded from. Since #3372 a fast-cleared upload
therefore reads its whole surface from guest memory wherever such an
import is possible, although nothing but that compare uses the copy.

ImportWatched now takes whether the import leaves its range watched. If
it does, the range is copied before the stores made so far are
collected, and after the import each page whose write protection was
resolved is compared with that copy. A page with other bytes is stamped
as a CPU store. A page with the same bytes keeps only the CPU-side stamp
the label rules read, so UnchangedSince holds for it for every consumer:
storage images tracked by layer, snapshots and caches as well.

If it does not (a host-pointer import on a device whose imports are
compared, a direct import on Windows), nothing is copied or compared:
the pages resolved in the window get the CPU-side stamp and the range
leaves the watch before the tracker is unlocked. Where host-pointer and
dma-buf imports differ in this, the dma-buf import that follows a failed
host-pointer import is a window of its own, so each window knows its
kind before it starts.

BlockMaybeWritten, the written-stamp table, WatchedImportsStampPages and
the unit compare in StorageTexture::Refresh are gone. The fast-clear
upload skips the guest-byte copy whenever its range is watched, as
before #3372.
2026-10-13 08:04:52 +13:00
David 1c7a8305b5
feat(libSceContentSearch): implement the search calls over an empty library
Cult of the Lamb (PPSA06465) imports libSceContentSearch, including
sceContentSearchGetContentLastUpdateId, OpenMetadataByContentId,
GetTotalContentSize and GetNumOfContent (import audit in #2686), which
were declared without parameters and threw.

Give the nine pending calls the signatures of AlexAltea/orbital
db_types.json (cc408367, lines 555-569) and SharpProspero
Interop/Content/ContentSearch.cs (5dfdb4b0), and implement the content
library the host has, which is empty:

- GetNumOfContent, GetTotalContentSize and SearchContent report 0 rows
  and 0 bytes, GetContentLastUpdateId and the search calls report update
  id 0. A search limit above 92 returns 0x809D100A and every call before
  Init returns 0x809D1001, both from SharpProspero.
- Filters and sort conditions use SharpProspero's layouts (added to
  SceTypes.hpp with size checks) and are checked against its enums;
  unknown values, null outputs and null arrays with a length throw.
- OpenMetadata and OpenMetadataByContentId throw, as no source gives the
  error for content that is not in the library, so no metadata id is
  handed out and CloseMetadata, GetMetadataFieldInfo and
  GetMetadataValue throw too.

The update id value, the argument errors and the check order are
recorded in TechnicalDebt. The four ContentSearch calls leave the
unimplemented-imports test, and guest_content_search covers the library.
2026-10-13 00:34:12 +05:30
p3nicillin dbecde00e0 feat(libSceNetCtlApDialog): run the offline access-point dialog lifecycle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:03:59 +01:00
LeandroLP23 67c943f119 docs(debt): drop the dup and select clauses from the random device entry
dup and dup2 carry the random device over to the new descriptor, and
select reports /dev/random and /dev/urandom ready, as the select entry
already says.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:02:33 +02:00
LeandroLP23 3e3b0a27ca docs(debt): mention --windows-gui and its lost output on the console entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:02:32 +02:00
Adrià d53960612f
Merge pull request #4686 from adriadam10/docs/roadmap-link
docs: replace COMPATIBILITY.md with a link to the blocker map
2026-10-12 21:02:25 +02:00
Eli Yarson f80a2f5535 fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
Titles check for a plugin with sceKernelStat before loading it through the engine path. The relinker emits only X.prx.guest.prx, so the check failed and PSNCore started with the raw (0, NULL) arguments. Share the dlopen mapping with sceKernelStat, read-only sceKernelOpen and sceKernelCheckReachability when the original name is absent.
2026-10-12 16:02:14 -03:00
Adrià Franch 7f51a6bcae docs: replace COMPATIBILITY.md with a link to the blocker map 2026-10-12 21:01:37 +02:00
LeandroLP23 d3011ae113 fix(libkernel): share the directory state between duplicated descriptors on Windows
dup and dup2 of a Windows directory descriptor threw. FreeBSD's
kern_dup makes both descriptors refer to one open file, so they share
the read position; the duplicate now points at the same DirectoryState,
which getdents and lseek go through, and keeps it after the original
is closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:01:33 +02:00
Yunus Shaikh a9c625acaf fix(shader): return 0 for 8-bit UNORM color comparison
image_sample_c on an 8-bit UNORM T# returns 0 for every compare
function on gfx1035, as on 8-bit sRGB (measured on the hardware oracle
in the review of #3438), but the emulated comparison still compared the
red channel. 8, 8_8 and 8_8_8_8 UNORM now return 0 like 8-bit sRGB.

Every texel comparison of those formats is 0, so a bilinear cube
without DISABLE_CUBE_WRAP and an anisotropic S# cannot change the
result; both are accepted for them, as the cube already was for 8-bit
sRGB. Other formats keep both refusals.

The test rows that check real comparisons move to 16_16 UNORM.
2026-10-12 12:00:21 -07:00
jagrat Singh dbce47244b feat(libkernel): implement sceKernelGetLibkernelTextLocation 2026-10-13 00:30:15 +05:30
fdfawef324 0ca047e60d fix(libc): size collate<char>::do_transform strings as the console does
collate<char>::do_transform gave the result std::string a capacity of
exactly its length and threw for results of 4095 characters or more.
The console's libc.prx grows the string from its inline capacity of 15
to length | 15, so a 26-character result has capacity 31 and a 32-byte
allocation. Once capacity + 1 reaches 0x1000 bytes it takes the
over-aligned large allocation that the guest's inlined deallocation
expects: operator new(bytes + 0x27), the data aligned to 32 bytes and
the raw pointer stored just before it. This is the scheme of
Dinkumware's basic_string (_Newsize | _ALLOC_MASK) and of its
_Allocate in <xmemory0> (_BIG_ALLOCATION_THRESHOLD 4096,
_BIG_ALLOCATION_ALIGNMENT 32, _NON_USER_SIZE sizeof(void*) + 31),
including its bad_alloc when bytes + 0x27 would wrap.

do_transform now uses that capacity and allocation; the throw for long
results is gone. The debt entry in docs/dev/debt/libc.md now records
the capacity and large storage as unverified on hardware. guest_collate
checks the capacity and allocation size of a 26-character result, the
last small result (4079 characters, a 4080-byte block) and the first
large one (4080 characters, capacity 4095, a 4096 + 0x27-byte block
with the data aligned to 32 and the raw pointer before it). With main's
LocaleSupport.cpp it aborts at the allocation-size check of the
26-character result (lastSize 27 instead of 32).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:59:36 -04:00
Yunus Shaikh d0cef9afdb test(libSceNet): define and run CheckEpollWritable before CheckPoolStats
#4673 adds a test after CheckEmptyEpoll and its call after CheckEmptyEpoll(), so placing the new check there made the two pull requests conflict.
2026-10-12 11:57:27 -07:00
Yunus Shaikh 78d594d9f6 Merge remote-tracking branch 'origin/main' into fix/libscenet-epoll-out 2026-10-12 11:56:48 -07:00
jagrat Singh 057b8108b3 feat(libkernel): implement setregid
Follow FreeBSD sys_setregid and root identity model: accept real and effective group id 0 or -1 (unchanged) and change nothing; any other id throws. Update GuestCredentials test and TechnicalDebt.
2026-10-13 00:25:13 +05:30
Adrià a60f52e318
Merge pull request #4400 from adriadam10/ci/stale-conflict-warning
ci: remind stale conflicting pull requests to rebase
2026-10-12 20:54:11 +02:00
Yunus Shaikh ac8106bda2 refactor(libSceNet): define timeout_option before receive_error
#4673 adds a function after receive_error, so defining timeout_option there made the two pull requests conflict.
2026-10-12 11:52:49 -07:00
Dean Galvin 59db660f7b test(agc): reserve the arena host hole the write-tracking checks query
On Windows the guest arena is reserved while libc loads, around whatever
the process has already mapped in its interval. About one start in forty
has nothing mapped there, so the arena has no host hole:
agc_driver_graphics then fails with "write-watched arena contained no
host exclusion to test" and agc_write_tracking prints that its host-hole
checks were skipped.

agc_write_tracking now starts itself suspended, reserves one allocation
granule in the middle of the child's arena interval before the child's
loader runs, and the child runs the host-hole checks on that range. The
range is a host hole on every start, so the checks no longer depend on
the address layout. The four queries agc_driver_graphics made on an
enumerated hole are among them and are removed there.
2026-10-13 07:47:05 +13:00
David f3a6edfccb feat(libSceShare): implement sceShareCaptureVideoClipExtended
Imported by the Share plugin of Hollow Knight: Silksong (PPSA12544).
Takes the extended parameter and request id like
sceShareCaptureScreenshotExtended, as KytyPS5 does: nothing is
captured, so it stores the invalid request id -1 when the pointer is
not null and returns NOT_SUPPORTED.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 245090904b64354f68fba3b8ef6fd6e232a3b1e6)
2026-10-12 18:46:45 +00:00
Adrià Franch 92aa5b971c docs(technical-debt): drop stale EAAccess unknown-info line and move the new one off the section end
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 18:46:44 +00:00
David e2954aa188 feat(libSceNpPartner001): implement sceNpEAAccessInitialize and sceNpEAAccessTerminate
UFC 6 (PPSA23566) imports both. Initialization marks the library
initialized and termination clears it, as in shadPS4. Termination
without initialization and a second initialization throw, since no
PS5 source settles their results.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit d2866a886a7702cdaad56d161460a3ce86ede629)
2026-10-12 18:46:44 +00:00
David 2dc4d9d65c feat(libSceAmpr): implement std::_Throw_Cpp_error
Throw a guest std::system_error for the Dinkumware _Cpp_error codes,
as in VC12 and microsoft/STL thread0.cpp: the error_code holds the
FreeBSD errno and a guest generic error category modelled in libc, and
what() is the table message followed by the category message. Codes
outside the table throw std::out_of_range. The system_error copy
constructor and assignment now copy the error_code too.

Imported by Deathloop (PPSA01670) and Minecraft Legends (PPSA05510).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit bed1deafdee4b50bea9683a1cead0d0320150eb7)
2026-10-12 18:46:43 +00:00
David 1d67426ede feat(libSceLibcInternal): implement getopt and getopt_long
Export getopt (VUtibKJCt1o) and getopt_long (8VVXJxB5nlk) from
libSceLibcInternal together with the guest variables optind
(zCnSJWp-Qj8), optarg (zG0BNJOZdm4), opterr (yaFXXViLWPw), optopt
(FwzVaZ8Vnus) and optreset (CZNm+oNmB-I). The NIDs were computed with
tools/nid_names.py and all seven are in aerolib; the PS5 payload SDK
f5d40f02 lists the functions and the five objects in
sce_stubs/libSceLibcInternal.c.

Titles (predicted stops from registry order, not observed runs):
- XPSemu PPSA97358, after execv/execve, the signal waits, the
  credential setters, mlockall and tcsendbreak:
  "FAIL: unresolved ELF import VUtibKJCt1o from libSceLibcInternal.prx"
  (getopt idx 204, 10 call sites from 0xF6C23D), then optind (207),
  optreset (208), optarg (209).
- RetroArch PPSA99169: getopt_long (idx 554, call sites 0xD2FC0C,
  0xD3002A), optind (553), optarg (555).

Behaviour follows FreeBSD release/11.4.0 8c639945: getopt is
lib/libc/stdlib/getopt.c (no permutation, GNU "::" optional argument,
lone "-" as an option when listed), getopt_long is getopt_internal
from lib/libc/stdlib/getopt_long.c with GNU_COMPATIBLE (permutation,
POSIXLY_CORRECT read through the guest getenv on the first call and on
optreset, "+" and "-" prefixes, "W;", optind 0 as a reset, abbreviation
and ambiguity rules and the GNU warning texts). Warnings are written to
the guest stderr stream as "<__progname>: <message>", as warnx does.
The struct option layout and argument kinds are include/getopt.h.
The code lives in libSceLibcInternal because __progname is a libkernel
export that libc cannot link.

A null getopt option string, a null argument vector or argument, a
negative optind and an optind moved inside a pending permutation throw
where FreeBSD faults. getopt_long_only is not exported.

guest_getopt runs the FreeBSD getopt_test cases (contrib/netbsd-tests
t_getopt.sh with the h_getopt and h_getopt_long result format) plus
grouped and optional arguments, "--", permutation order, "+" and "-"
prefixes, optreset and optind 0 restarts, POSIXLY_CORRECT, all three
long argument kinds, abbreviations, ambiguity, flag pointers, "W;",
optopt with opterr 0 and the exact stderr text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit a2740166d93920c301e1add23ceea762b4acad27)
2026-10-12 18:46:43 +00:00
MarcZX100 acd821f7ce fix(tools): audit sectionless guest modules 2026-10-12 18:46:25 +00:00
Leandro Soares 6054923cd5 fix(tools): audit the imports of --modules files
(cherry picked from commit 2d0d707802c190f4d8ed93d01427576accbc08b1)
2026-10-12 18:46:25 +00:00
Scramblrrrr 3824282e59 test(agc): keep queue zero alive after an interrupted storage idle wait 2026-10-12 18:46:24 +00:00
MarcZX100 afbc3c8eb5 fix(agc-driver): delay storage writeback until queue activity settles 2026-10-12 18:46:24 +00:00
MarcZX100 cf25df9a62 test(cmake): serialize load-sensitive Windows tests 2026-10-12 18:46:19 +00:00
Hussein Kadhim df8f3097be fix(libkernel): accepted sockets inherit the listener's non-blocking mode
FreeBSD accept() copies SS_NBIO from the listening socket (ACCEPT4_INHERIT in
kern_accept4). The accepted guest socket was always recorded as blocking:
fcntl(F_GETFL) never showed O_NONBLOCK, and the host socket kept the host's own
inheritance (kept on Windows, dropped on Linux). Apply the listener's mode to
the accepted socket.
2026-10-12 18:46:10 +00:00
MarcZX100 32b0c8d79a test(libc): cover null readdir_r result pointer 2026-10-12 18:46:05 +00:00
David ce4e6ce839 feat(libc): implement readdir_r
VLC PPSA85300 imports readdir_r (J0kng1yac3M) from
libSceLibcInternal.prx. Predicted stop after getlogin_r, from relink
registry order (idx 343, call site 0x16A0B91):
  FAIL: unresolved ELF import J0kng1yac3M from libSceLibcInternal.prx

The NID is readdir_r in aerolib (tools/nid_names.py --nid J0kng1yac3M:
rename-ready readdir_r); the title binds it to libSceLibcInternal, where
the PS5 payload SDK (ps5-payload-dev/sdk f5d40f02,
sce_stubs/libSceLibcInternal.c) lists it beside readdir, so it goes into
libc next to readdir.

FreeBSD 11.4 (freebsd-src 8c639945, lib/libc/gen/readdir.c:106-135):
save errno and clear it, take the stream lock, read the next entry and
copy _GENERIC_DIRSIZ(dp) bytes of it into the caller's entry, set
*result to the entry or NULL at the end, return errno when the read
fails, otherwise restore errno and return 0. The guest struct dirent is
the SDK's FreeBSD 11 layout (include/freebsd/sys/dirent.h, 264 bytes,
name at 8), and _GENERIC_DIRSIZ equals the recordLength readdir already
computes. The read itself is readdir's, moved into a helper that both
call under the per-stream mutex, so readdir and readdir_r share one
position. A null stream returns EBADF, as readdir sets it; a null entry
or result pointer throws instead of faulting.

The call site is libbluray 1.4.1 _dir_read_posix
(videolan/libbluray 7d94f266, src/file/dir_posix.c:73-88), reached when
VLC opens a Blu-ray folder or ISO. The disassembly at 0x16A0B91 passes a
264-byte stack buffer (sizeof(struct dirent)) and reads d_name at
offset 8.

Tested on Windows (MinGW): guest_directory 3/3 (readdir_r over a
temporary directory to the end gives the same names and types as
readdir, copies only recordLength bytes, keeps errno at the end,
continues the position of an interleaved readdir, EBADF for a null
stream, throw for a null entry).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 01085afe122d6d2c6af9e54c745e2a7c448f7b24)
2026-10-12 18:46:05 +00:00
Blazing Cook c20583bd34 fix(ampr): reject command buffer offsets beyond bound memory
(cherry picked from commit b92287dc68d538d44369d2a09500b4404ca53fca)
2026-10-12 18:45:58 +00:00
Yunus Shaikh 2c0d8d48bc Merge remote-tracking branch 'origin/main' into fix/libc-strtod-quiet-nan-windows
# Conflicts:
#	docs/dev/TechnicalDebt.md
2026-10-12 11:45:40 -07:00
milescoviello 953ae58bc8 fix(libkernel): hold back new rwlock readers while a writer waits
Guest rwlocks were a host std::shared_timed_mutex. On Linux that is a
glibc rwlock, which prefers readers: a reader is let in while a writer
is blocked, so a writer waiting on a lock that readers keep taking in
overlapping turns never gets it (a probe with four readers each holding
the lock for 4 ms still had scePthreadRwlockWrlock waiting after 5 s,
with 4924 read acquisitions meanwhile), and tryrdlock succeeds while a
writer waits.

FreeBSD 11.4 libthr gives waiting writers precedence. A rwlock starts
without URWLOCK_PREFER_READER (rwlock_init() callocs it), and
lib/libthr/thread/thr_umtx.h, _thr_rwlock_tryrdlock(), refuses a reader
while a writer waits:

	if ((flags & URWLOCK_PREFER_READER) != 0 ||
	    (rwlock->rw_flags & URWLOCK_PREFER_READER) != 0)
		wrflags = URWLOCK_WRITE_OWNER;
	else
		wrflags = URWLOCK_WRITE_OWNER | URWLOCK_WRITE_WAITERS;

as does do_rw_rdlock() in sys/kern/kern_umtx.c for the blocking wait.
The only exception is a thread that already holds a read lock, so that a
recursive read cannot deadlock (lib/libthr/thread/thr_rwlock.c,
rwlock_rdlock_common()):

	if (curthread->rdlock_count) {
	...
		flags = URWLOCK_PREFER_READER;

The rwlock is now a mutex and condition with a count of waiting writers:
a reader waits while a writer holds the lock or, unless the thread
already holds a read lock, while a writer waits; a timed writer that
gives up wakes the readers it held back. The TechnicalDebt note about
locking guest rwlocks once for winpthreads no longer applies to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:43:43 +00:00
screamm 43ffba87e4 feat(libkernel): implement fcntl record locks on Windows
ProsperoRadio (PPSA99001) stops at 33.7 s on Windows, with #3649
applied so that it gets past poll, on the throw from #3840:

    what():  fcntl: record locks are not implemented on Windows, command=12, fd=3

F_GETLK, F_SETLK, F_SETLKW and the F_OGETLK, F_OSETLK and F_OSETLKW
forms now follow FreeBSD 11.4's kern_fcntl and lf_advlockasync
(8c639945): an SEEK_CUR start is resolved against the descriptor offset
(EOVERFLOW past OFF_MAX), F_RDLCK needs read access and F_WRLCK write
access (EBADF), another type is EINVAL, and the range is checked against
the file size for SEEK_END (EINVAL for a negative start or an unknown
whence, EOVERFLOW past OFF_MAX). The guest is one process, and
lf_blocks never lets locks of one owner conflict, so whichever
descriptor or thread asks, F_SETLK and F_SETLKW succeed without waiting
and F_GETLK reports F_UNLCK, as on the console. Nothing is held on the
host: Windows byte-range locks are mandatory and would fail the guest's
own reads and writes through other descriptors. A lock from the end of
a directory throws.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 18:42:53 +00:00
Adrià 1acfa7f788
Merge pull request #4411 from adriadam10/docs/debt-per-library
feat(tools): keep technical debt in one file per library
2026-10-12 20:39:57 +02:00
Adrià Franch 342a8c4590 docs(debt): move library entries to one file per library
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 20:38:29 +02:00
Adrià Franch 555099ae23 feat(tools): keep technical debt in one file per library
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 20:38:17 +02:00
Dean 1b92f7f5dc
Merge pull request #4605 from AlxcBTW/fix/agc-dword-pattern-fill-format
fix(agc): take the dword pattern-fill kernel only through a 32-bit output format
2026-10-13 07:35:32 +13:00
Superhe11 faf1cd77c6 fix(relinker): validate the ELF object version and header size 2026-10-12 21:35:13 +03:00
Dean 9d3629cc91
Merge pull request #4268 from AlxcBTW/fix/vop3p-int-neg
fix(shader): apply VOP3P neg_lo/neg_hi to packed 16-bit integer sources
2026-10-13 07:35:10 +13:00
Dean ed47df8ba9
Merge pull request #4385 from AlxcBTW/fix/host-import-retire-hold
fix(agc): keep a host import dropped mid-hold for every batch that hold opens
2026-10-13 07:34:49 +13:00
Dean c90404f97a
Merge pull request #4518 from AlxcBTW/fix/bda-unaligned-dword-write
fix(shader): store unaligned 32-bit BDA writes byte by byte
2026-10-13 07:34:34 +13:00
Dean 0c75934f5f
Merge pull request #4470 from overlordxrz-source/fix/vertex-one-lane-waves
fix(recompiler): run vertex programs as one-lane waves without vertex subgroups
2026-10-13 07:34:13 +13:00
Dean 9f7c40e36f
Merge pull request #4389 from ivica00/fix/rect-list-invariant-position
fix(shader): decorate rect-list gl_Position as Invariant
2026-10-13 07:33:51 +13:00
David 61fbec8ef1 fix(libkernel): fail lseek on a pipe with ESPIPE on Windows 2026-10-12 18:33:31 +00:00
Dean 5d933db02e
Merge pull request #4364 from SleglJan/fix/structurizer-return-join
fix(recompiler): give an early-return selection a merge when its parent's other arm reaches the same join
2026-10-13 07:33:30 +13:00
Dean 9df77462cc
Merge pull request #4544 from poonasor/feat/libkernel-module-info2
feat(libkernel): implement sceKernelGetModuleList2 and sceKernelGetModuleInfo2
2026-10-13 07:33:08 +13:00
Dean ee966bb747
Merge pull request #4542 from saxopa/fix/relinker-sce-relro
fix(relinker): load a PT_SCE_RELRO segment that no PT_LOAD covers
2026-10-13 07:32:37 +13:00
Dean 9c99f43440
Merge pull request #4537 from coltken95/claude/sleepy-dirac-e44kw4
fix(libc): sort with FreeBSD 11's qsort so equal elements keep its order
2026-10-13 07:32:15 +13:00
Dean 21c27e60a4
Merge pull request #4536 from orishamir/fix/debugout-host-stderr
fix(libkernel): keep sceKernelDebugOutText off a redirected guest stderr
2026-10-13 07:31:53 +13:00
Dean a29ea3a2e3
Merge pull request #4529 from NahuelGenchi/fix/libc-new-length-error
fix(libc): throw bad_alloc from operator new when the default heap rejects a size
2026-10-13 07:31:32 +13:00
Dean 455027e520
Merge pull request #4528 from kr4y4/test/agc-dot2-rounding-float64-skip
test(agc): skip the f32 dot2 rounding test on devices without shaderFloat64
2026-10-13 07:31:10 +13:00
Dean 3b5c96377d
Merge pull request #4516 from Ondra97/codex/file-lock-lifetime
fix(libs): share Windows flock state between duplicated descriptors
2026-10-13 07:30:48 +13:00
Dean f7b238e43b
Merge pull request #4513 from winstrex/fix/libkernel-open-directory-trailing-separator
fix(libkernel): open directories whose host path ends in a separator on Windows
2026-10-13 07:30:26 +13:00
Dean 66013d910b
Merge pull request #4511 from rebelittle/fix/windows-seh-unwind
fix(libc): unwind guest exceptions through Windows DLL frames
2026-10-13 07:30:11 +13:00
Dean 4756c051ef
Merge pull request #4504 from yunusshaikh7/fix/savedata-dir-name-trailing-wildcard
fix(savedata): let a trailing % in a directory name pattern match nothing
2026-10-13 07:29:49 +13:00
Dean acbaa8a16d
Merge pull request #4495 from SibteProf/fix/relinker-sdk-mman-syscalls
fix(relinker): recognize SDK memory syscall trap patterns
2026-10-13 07:29:18 +13:00
Dean 4a49cda98f
Merge pull request #4492 from ideabsassistenza/fix/pad-input-persistent-sequence
fix(pad-input): preserve command ordering across clock resets
2026-10-13 07:28:56 +13:00
Dean 2350fa5353
Merge pull request #4489 from Dripl1x/codex/guest-export-index
perf(relinker): index guest exports for dependency resolution
2026-10-13 07:28:34 +13:00
Dean e305bc4e4a
Merge pull request #4483 from fable-void/pr/relinker-jump-table-targets
fix(relinker): treat jump table targets as branch targets when moving instructions
2026-10-13 07:28:12 +13:00
Dean 9907993e5f
Merge pull request #4473 from arcwiser/fix/pr-overlap-fetch-batches
fix(tools): batch pr_overlap fetch refspecs
2026-10-13 07:27:51 +13:00
Dean 60f4c71608
Merge pull request #4466 from babyhuey/feat/libkernel-socid-cpumode
feat(libkernel): export sceKernelGetMainSocId, sceKernelGetCpumode and sceKernelGetCpuFrequency
2026-10-13 07:27:28 +13:00
Dean d4ccf91e03
Merge pull request #4462 from milescoviello/carry/libc-umodti3-4460
feat(libc): implement __umodti3
2026-10-13 07:27:06 +13:00
Dean b9f194a890
Merge pull request #4455 from SibteProf/fix/libc-secure-copy-size-limits
fix(libc): reject oversized secure copy destinations
2026-10-13 07:26:35 +13:00
Dean 91e263824e
Merge pull request #4452 from orishamir/fix/relinker-null-symbol-imports
fix(relinker): resolve relocations against null symbol entries to 0
2026-10-13 07:26:13 +13:00
Yunus Shaikh 0a1dff2fcc perf(agc): read the draw snapshot cap when resources are built
ShaderResources::PrepareDrawBindings called MaxDrawSnapshotBytes() on
every draw, and it read APS5_DRAW_SNAPSHOT_MAX_MIB with getenv each
time. The UCRT's getenv takes the environment lock and scans the whole
block. In Planet of Lana (about 90,000 draws per 10 s) that call was
2.6% of the queue-0 worker's samples.

The cap is now read once when a ShaderResources object is built and
kept in it, so a cached resource template uses it for every draw it
serves. In Planet of Lana the record phase drops from 21.2 to 18.7 us
per draw.

drawSnapshotCapTests also raises the variable after building the
resources and checks that they keep the cap they were built with. With
the previous ShaderResources.cpp it fails there.
2026-10-12 11:26:09 -07:00
Dean 715bfabdac
Merge pull request #4426 from babyhuey/feat/libc-overflow-error
feat(libc): export std::overflow_error type info, vtable and destructor
2026-10-13 07:25:42 +13:00
Dean 45e1b80636
Merge pull request #4421 from Lorkydey/fix/nid-names-invalid-cli-nids
fix(tools): reject invalid NIDs in the name lookup CLI
2026-10-13 07:25:21 +13:00
Dean 5d3e1740ff
Merge pull request #4420 from Lorkydey/fix/check-skips-disabled-tests
fix(ci): reject disabled CTest cases in skip validation
2026-10-13 07:25:00 +13:00
Dean 30e169127d
Merge pull request #4419 from Ondra97/codex/deferred-module-lifetime
fix(libkernel): bind deferred initialization to the loaded image
2026-10-13 07:24:39 +13:00
Dean 6f47d9117f
Merge pull request #4416 from muhzain05/fix/videodec2-picture-owner
fix(videodec2): answer picture info from the decoder that last wrote the buffer
2026-10-13 07:24:18 +13:00
Dean 3ede42aace
Merge pull request #4414 from AchrafReyani/fix/agc-single-sample-scan-into-msaa-target
fix(agc): rasterize a single-sample scan into a multisampled target at the pixel center
2026-10-13 07:23:57 +13:00
Dean 31ade9abc2
Merge pull request #4406 from Onny2/test/sce-net-absolute-invalid-name
test(net): look up the unresolvable name as an absolute name
2026-10-13 07:23:34 +13:00
Dean 83e6be8a69
Merge pull request #4394 from AaravMehta-07/codex/sce-net-stream-sender
fix(libSceNet): preserve successful stream recvfrom results
2026-10-13 07:23:13 +13:00
Dean 57f91221c4
Merge pull request #4380 from AzazelSensei/fix/libc-stream-errors
fix(libc): return stream errors from fwrite, fread and fputs instead of throwing
2026-10-13 07:22:52 +13:00
Dean b5546111b6
Merge pull request #4373 from milescoviello/fix/recvmsg-seqpacket-trunc
fix(libkernel): report MSG_TRUNC for SOCK_SEQPACKET records in recvmsg
2026-10-13 07:22:38 +13:00
Dean b701bc5d8d
Merge pull request #4372 from milescoviello/fix/fflush-read-stream
fix(libc): leave a stream that is reading untouched in fflush on Linux
2026-10-13 07:22:17 +13:00
Dean 3377986a60
Merge pull request #4371 from milescoviello/fix/net-socket-timeval-timeouts
fix(libSceNet): read setsockopt timeouts as struct timeval
2026-10-13 07:21:55 +13:00
Dean edddd6a17b
Merge pull request #4370 from milescoviello/fix/ipv6-only-sockets
fix(net): make new IPv6 sockets IPv6-only as FreeBSD does
2026-10-13 07:21:34 +13:00
Dean 59a2167a93
Merge pull request #4368 from SandstromPL/fix/conventions-run-from-subdirectory
fix(conventions): check the whole repository when run from a subdirectory
2026-10-13 07:21:13 +13:00
Dean f30e89ee7c
Merge pull request #4365 from Gashrod1/fix/libc-strxfrm-truncation
fix(libc): truncate strxfrm like FreeBSD's C locale
2026-10-13 07:20:51 +13:00
Dean ee2c0f9b92
Merge pull request #4361 from Roojool/contrib/round2-c20
test(tools): support Python 3.10 in encoding regressions
2026-10-13 07:20:30 +13:00
Dean dfe9ccf6a2
Merge pull request #4360 from milescoviello/fix/wide-printf-grouping-flag
fix(libc): accept the ' flag in the wide printf family
2026-10-13 07:20:09 +13:00
Dean 15e64abd77
Merge pull request #4359 from milescoviello/fix/syslog-wide-format
fix(libc): format guest wide arguments in syslog on Linux
2026-10-13 07:19:47 +13:00
Dean 655cba83d5
Merge pull request #4358 from milescoviello/fix/scanf-binary-prefix
fix(libc): read %i without the C23 binary prefix in the scanf family on Linux
2026-10-13 07:19:26 +13:00
Dean 2c579b55f9
Merge pull request #4357 from milescoviello/fix/wide-printf-positional
fix(libc): format positional arguments in the wide printf family
2026-10-13 07:19:05 +13:00
Dean b538b28d8b
Merge pull request #4354 from milescoviello/fix/fopen-append-position
fix(libc): start append-mode streams at the end of the file
2026-10-13 07:18:50 +13:00
Dean bde332a59c
Merge pull request #4353 from milescoviello/fix/printf-errno-message
fix(libc): print the guest errno message for %m in the printf family
2026-10-13 07:18:29 +13:00
milescoviello eb9da23e68 fix(libkernel): accept socket option values longer than an int
setsockopt() on a guest socket failed with EINVAL unless the option
length was exactly sizeof(int), so an option passed as a 64-bit value
(for example SO_BROADCAST or SO_RCVBUF from an int64_t or size_t) was
rejected and silently left unchanged.

FreeBSD 11.4 reads these integer options through sooptcopyin() with the
size of an int as both the wanted and the minimum length, and only a
shorter value fails. sys/kern/uipc_socket.c, sooptcopyin():

	 * If the user gives us more than we wanted, we ignore it, but if we
	 * don't get the minimum length the caller wants, we return EINVAL.
	...
	if ((valsize = sopt->sopt_valsize) < minlen)
		return EINVAL;
	if (valsize > len)
		sopt->sopt_valsize = valsize = len;

and sosetopt() uses it for SO_BROADCAST, SO_REUSEADDR, SO_SNDBUF and
SO_RCVBUF:

	error = sooptcopyin(sopt, &optval, sizeof optval,
	    sizeof optval);

A longer value now sets the option from its first int; a shorter one
still fails with EINVAL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:04:27 +00:00
Yunus Shaikh c55f377fb0 refactor(libc): place the NaN helpers and test includes apart from neighbouring changes 2026-10-12 11:03:36 -07:00
Aarav f11798413e fix(libkernel): guard SCE pthread semaphore count overflow
Reject invalid initial counts without replacing the semaphore and preserve a saturated count on post, matching the existing guest POSIX limits with encoded SCE errors. Add boundary and unchanged-value guest regressions.
2026-10-12 23:26:25 +05:30
Gustavo Ariel Gamarra Rojas 554e615524 test(agc): check that a buffer written over pending storage results keeps both
A storage image is written on the GPU and left pending, then a leased
address-based use writes the first 40800 bytes of the same memory as a
buffer and every pending image is flushed: guest memory must hold the
buffer's bytes where it wrote and the image's texels everywhere else.
Runs with watched and with compared imports and returns 77 when host
imports or write watching are unavailable.
2026-10-12 14:52:44 -03:00
Gustavo Ariel Gamarra Rojas f4ff589679 fix(agc): store pending storage results before a use writes the same memory as a buffer
Before a dispatch or draw that writes buffer ranges is recorded, store the
results of storage images still pending in those ranges, whatever path
serves the range (in place, copied, or an address-based heap, which the
per-region flush exempts), and include the written ranges in the pending
scan of a revalidated resource set.

Without it the image's write-back could come after the buffer write: a
partial write to a 64 KiB block made the write-back keep the whole block,
dropping the image's results in the rest of it, and a write-back recorded
after the buffer write stored the image's older texels over it. Titles
that reuse transient memory for textures and buffers in the same frame
(Unreal Engine's render graph transient allocator) read corrupted tile
data as a result.
2026-10-12 14:52:44 -03:00
lorkydey c052b7c720 feat(libc): query filesystem statistics by guest path 2026-10-12 19:42:52 +02:00
milescoviello 11bda1c6a8 feat(libc): implement ceil
Kart PS5 (PPSA99611) stops on gacfOmO8hNs (ceil, per tools/nid_names.py)
from libc.prx once __umodti3 resolves (title run on #4519). ceil rounds
toward positive infinity whatever the rounding mode, keeps the sign of
zero and of results that round to zero, and returns infinities and NaNs
unchanged, as std::ceil does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:27:00 +00:00
MiniRML 63022e23cc Merge remote-tracking branch 'upstream/main' into fix/nid-windows-unicode-paths 2026-10-12 10:05:59 -07:00
MiniRML 69b6cb665f Merge remote-tracking branch 'upstream/main' into fix/kernel-json-number-locale 2026-10-12 10:05:55 -07:00
MiniRML a7799c4315 Merge remote-tracking branch 'upstream/main' into fix/nid-buffer-validation 2026-10-12 10:05:51 -07:00
QRMOE 79d88af192
test(libc): cover wide transform output bounds 2026-10-12 19:04:00 +02:00
QRMOE 22d03d497f
fix(libc): terminate truncated wcsxfrm results 2026-10-12 19:03:18 +02:00
QRMOE 0950b19854
test(libc): cover exhausted tokenizer state 2026-10-12 19:01:27 +02:00
MiniRML ad43a486f0 test(nid): keep reference registration independent of other topics 2026-10-12 10:00:50 -07:00
QRMOE 3cb434715a
fix(libc): clear exhausted strtok continuation state 2026-10-12 19:00:50 +02:00
MiniRML 1c500fb298 test(nid): separate export-reference registration from path tests 2026-10-12 09:59:52 -07:00
MiniRML 4df7877334 test(nid): avoid competing hash test registration 2026-10-12 09:57:43 -07:00
MiniRML 89d89ac048 fix(nid): preserve each ELF string consumer independently 2026-10-12 09:53:17 -07:00
MiniRML f25eba673d fix(nid): bound version requirement chains to their section 2026-10-12 09:51:20 -07:00
Borooooo 39bed4b9d7 fix(relinker): accept paths longer than 260 characters on Windows
relinker.exe carried only MinGW's default manifest, so Windows kept MAX_PATH for it even with long paths enabled, and an input under a deep directory failed with 'Cannot open file'. Embed a manifest with longPathAware that keeps asInvoker and the Windows 10 supportedOS entry.
2026-10-12 18:50:50 +02:00
MiniRML 617e7acfa8 test(nid): avoid competing hash test registration 2026-10-12 09:46:59 -07:00
MiniRML abe8fb8193 fix(nid): validate ELF table layouts before patching 2026-10-12 09:45:30 -07:00
Claude 1285ee06f5
fix(shader): keep a folded selection's branch when SPIR-V 1.6 forbids one label
The previous commit pointed the untaken side of a folded branch that
keeps its selection merge at the merge block. That adds an edge from the
header to the merge block: the merge block's phis have no operand for it,
and values from the taken arm no longer dominate the merge block, as
fuzzing with validation on found once the repeated label stopped hiding
it.

For SPIR-V 1.6 the branch is now left as it is, so the control flow and
the untaken arm stay; earlier versions keep naming the taken label twice,
which they allow, and drop the untaken arm as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-12 16:40:43 +00:00
MiniRML bb443667ec fix(nid): validate GNU hash geometry before rewriting 2026-10-12 09:39:28 -07:00
MiniRML 6e0f942f0f fix(nid): resolve PE reference exports through their ordinals 2026-10-12 09:36:42 -07:00
Rujul Talekar 0c52b2a0b0 fix(tools): use configured CMAKE_MAKE_PROGRAM for test registration audit
tools/check_test_registration.py invoked bare ninja from PATH, so the audit failed with FileNotFoundError when the configured Ninja lived outside PATH. Read CMAKE_MAKE_PROGRAM from the build directory CMakeCache.txt and fail honestly when it is missing. Adapt the mocked built tests to a configured build and add a regression that runs a real Ninja from a path with spaces outside PATH.
2026-10-12 21:59:53 +05:30
MiniRML db577b4a34 fix(release): preflight asset destination types 2026-10-12 09:29:03 -07:00
Nithishvelan M 98e0fb0dcd
fix(libSceWebBrowserDialog): permit termination from finished state in sceWebBrowserDialogTerminate 2026-10-12 21:58:02 +05:30
MiniRML 17a3d8a1a0 fix(oracle): honor current target override 2026-10-12 09:27:33 -07:00
MiniRML 521cc95b18 fix(oracle): validate input words before tool lookup 2026-10-12 09:26:05 -07:00
Claude 52b679c552
fix(shader): keep the back-edge of a loop whose continue block is dead
Pipeline specialization replaced every unreachable block with
OpUnreachable. When a loop's continue target became unreachable, either
because the latch exited on a constant condition or because the emitter
had already folded it, that removed the header's only back-edge, and
validation rejects a loop header targeted by no back-edge block.

An unreachable continue target of a live loop header now keeps an
OpBranch to its header, as SPIRV-Tools' dead branch elimination does.
The header's phis keep an operand for it, naming the phi itself, since
the edge is never taken and the continue block's values are gone.

Found by recompiling mutated compute shaders with SPIR-V validation on,
for loops with a literal bound such as s_cmp_lt_u32 with two constants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-12 16:25:22 +00:00
MiniRML 53d10eac9a fix(tools): exclude cut helpers from NID accounting 2026-10-12 09:24:13 -07:00
AlxcBTW 81e4638254 docs: add a performance report issue form and ask for summary lines
.github/ISSUE_TEMPLATE/performance.yml asks for the title and scene, what is
slow or what changed, the summary lines and traces of APS5_TRACE_FRAMES
captures, the trace digest and optionally the worker's collapsed stacks,
and states the capture protocol: warm caches, the same scene and settings,
no other profiling switch, the same machine and session. The pull request
template and CONTRIBUTING ask a pull request that claims a change in speed
for the summary lines of main and of the change, captured the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:23:52 +02:00
PrintOrb 9c007805d6
Merge branch 'main' into fix/videoout-high-frame-rate 2026-10-12 11:15:48 -05:00
MiniRML a6f42f5119 fix(relinker): zero the unmapped section-name table address 2026-10-12 09:10:47 -07:00
Simon 50deecc122 fix(agc): count every CP data write of a dispatch group as a write of the run
The compute dispatch look-ahead noted WRITE_DATA and RELEASE_MEM stores only
as labels, and labels other than 4 or 8 bytes were dropped. A WRITE_DATA that
fills a descriptor or an argument block between two dispatches was invisible,
so the later dispatch was captured ahead with the old bytes. Every such store
now also enters the run's written ranges, which stop the look-ahead before a
dispatch that reads them.
2026-10-12 18:09:14 +02:00
MiniRML 7dfd790d08 fix(release): find the configured Windows runtime 2026-10-12 09:05:52 -07:00
Yunus Shaikh aa4a9b4faf fix(libc): return the default quiet NaN from the strtod family
C17 7.22.1.3 and 7.29.4.1.1 interpret NAN(n-char-sequence) as a quiet
NaN. With MinGW-w64, std::strtod, strtof and strtold are mingw-w64's
gdtoa functions, which copy the hex digits into the significand
without the quiet bit, and for long double without the x87 integer
bit: strtod("nan(0x123)") returned the signaling NaN
0x7ff0000000000123 and strtold a pseudo-NaN. A payload whose only set
bit is the implicit or x87 integer bit gave infinity:
strtof("nan(0x800000)"), strtod("nan(0x10000000000000)") and
strtold("nan(0x8000000000000000)") returned +inf. glibc returns quiet
NaNs that keep the payload.

C17 7.12.11.2p2 makes nan("n-char-sequence") equivalent to
strtod("NAN(n-char-sequence)", NULL), and nan and nanf already return
the console's fixed quiet NaNs, ignoring the tag. ParseFloat, which
strtod, strtof, strtold, atof and the wide variants share, now returns
the same values, 0x7ff8000000000000 and 0x7fc00000, negated after a
minus sign, on Windows and Linux. strtold returns the x87 default
quiet NaN, since no console nanl was observed.
2026-10-12 09:04:31 -07:00
Claude 7fd423dfe9
fix(shader): never branch conditionally to one label twice
SPIR-V 1.6 requires the true and false labels of OpBranchConditional to
differ. Two places produced the same label for both:

- The structured terminator emitter, for a conditional branch whose
  targets are the same block, such as s_cbranch_scc0 to the next
  instruction. It now emits OpBranch, keeping OpLoopMerge on a loop
  header.
- Pipeline specialization, when it folded a branch on a constant and
  kept the selection merge because the taken path is not linear. It
  wrote the taken label twice; the untaken side now names the
  selection's merge block, which the constant condition never takes.

Found by recompiling mutated compute shaders with SPIR-V validation on;
before this, 169 of 20000 were rejected for this rule, and builds
without SPIRV-Tools handed the module to the driver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-12 16:04:13 +00:00
Yunus Shaikh 4f78bd534f fix(libSceNet): report copied socket address lengths
sceNetAccept, sceNetGetsockname, sceNetGetpeername, sceNetRecvfrom and
sceNetRecvmsg stored the full address length (16 or 28) even when the
caller's buffer was shorter and only part of the address was copied.
FreeBSD 11.4 stores the copied length, the smaller of the two
(kern_accept4, kern_recvit, kern_getsockname and kern_getpeername in
sys/kern/uipc_syscalls.c), as libkernel's socket calls do since #4295.
2026-10-12 09:00:04 -07:00
Yunus Shaikh feffc67acb fix(libSceNet): name an unbound socket with the zero address on Windows
sceNetGetsockname on a socket that is neither bound nor connected failed
with EINVAL on Windows, where Winsock reports WSAEINVAL. FreeBSD 11.4
returns the wildcard address with port 0 (in_getsockaddr and
in6_getsockaddr in sys/netinet/in_pcb.c and sys/netinet6/in6_pcb.c), and
Linux already does, so the call now builds that address for the socket's
family.
2026-10-12 09:00:04 -07:00
Yunus Shaikh 53cbdebe82 fix(libSceNet): report the registered socket as the epoll event ident
sceNetEpollWait copied the whole event a title passed to
sceNetEpollControl, so the ident and reserved fields came back as the
title had left them. The ident of a returned event is the id that was
registered and reserved is 0 (shadPS4 net.cpp sceNetEpollWaitImpl,
KytyPS5 network.cpp EpollWait); a title that registers a socket without
filling ident and looks the socket up by it now finds it.
2026-10-12 09:00:03 -07:00
Yunus Shaikh b19a74f5bf fix(libSceNet): sceNetEpollWait takes 2 as the OUT event
sceNetEpollWait used Linux's EPOLLOUT bit (4) for writability. The SCE
value is 2 (shadPS4 net_types.h ORBIS_NET_EPOLLOUT, KytyPS5 network.cpp
EPOLL_OUT, SharpProspero Socket.cs EpollOut); IN (1), ERR (8) and HUP
(0x10) already match. A socket registered for OUT was never polled for
writability, so the wait ran out its timeout or blocked forever, and an
IN|OUT registration never reported OUT.
2026-10-12 09:00:02 -07:00
Yunus Shaikh febc36223b fix(libSceNet): take 0x1105 and 0x1106 as the send and receive timeouts
sceNetSetsockopt and sceNetGetsockopt answered EOPNOTSUPP for 0x1105 and
0x1106, the SCE send and receive timeouts in microseconds (shadPS4
net_types.h ORBIS_NET_SO_SNDTIMEO/RCVTIMEO, SharpProspero Socket.cs
SoSndTimeo/SoRcvTimeo, KytyPS5 network.cpp). A title that set a receive
timeout this way then blocked in sceNetRecv for good. Both options now
set and read the timeouts that 0x1005 and 0x1006 already do.
2026-10-12 09:00:02 -07:00
Dean 2a5eca11cd
Merge pull request #4350 from milescoviello/fix/once-reset-on-exit
fix(libkernel): reset a once control when its initializer exits or is cancelled
2026-10-13 04:53:46 +13:00
Dean a7614930a4
Merge pull request #4349 from milescoviello/fix/open-nofollow
fix(libkernel): fail open with O_NOFOLLOW on a symbolic link
2026-10-13 04:53:25 +13:00
Dean 3881117feb
Merge pull request #4348 from milescoviello/fix/rmdir-symlink
fix(libkernel): fail rmdir on a symbolic link instead of removing it
2026-10-13 04:53:02 +13:00
Dean d3187dff7f
Merge pull request #4346 from SandstromPL/fix/relinker-registry-after-patch
fix(relinker): write registries after the executable
2026-10-13 04:52:40 +13:00
Dean 57f5ec232c
Merge pull request #4338 from ArjenS-LA/fix/diagnostic-input-preservation
fix(relinker): preserve inputs when writing Windows diagnostics
2026-10-13 04:52:18 +13:00
Mohamed Aziz Hadjkacem 4d37c93364 fix(agc,shader): prime the two host shared mutexes added after 48dcaace7
Commit 48dcaace7 introduced PrimedSharedMutex and converted every host std::shared_mutex that existed at the time, because winpthreads initializes a static rwlock on first use and a concurrent first lock returns EINVAL, which std::shared_mutex ignores (docs/dev/TechnicalDebt.md:10).

Two host mutexes were added afterward and missed the conversion:
- Recompiler.cpp registrationModule() static mutex (added by baf3437465)
- MultisampleTarget.cpp guardedMutex() static mutex (added by d109f3966f)

Apply the same priming. Recompiler.cpp reuses the PrimedSharedMutex already defined in that translation unit; MultisampleTarget.cpp gets the identical local helper to match the existing inline precedent.

Tested: Windows 11 x64, WinLibs GCC 15.2.0 (matches CI). Compiled Recompiler.cpp.obj and all three MultisampleTarget.cpp.obj targets with the project build flags; check_conventions.py passes.
2026-10-12 16:52:00 +01:00
Dean 0a6bb6ac51
Merge pull request #4337 from ArjenS-LA/fix/windows-origin-slash
fix(relinker): accept trailing separators on the Windows origin path
2026-10-13 04:51:57 +13:00
Dean 05f6460165
Merge pull request #4336 from ArjenS-LA/fix/guest-runpath-list
fix(relinker): rebase each origin in guest runpath lists
2026-10-13 04:51:37 +13:00
Dean 63d4a10999
Merge pull request #4335 from ArjenS-LA/fix/test-registration-reachability
fix(tools): ignore unreachable CTest registration files
2026-10-13 04:51:15 +13:00
Dean b8fff28bd0
Merge pull request #4330 from treuenten/claude/peaceful-darwin-etpdf0
fix(tools): follow Depends on chains in pr_overlap
2026-10-13 04:50:54 +13:00
Dean 97445386fe
Merge pull request #4328 from pipe1os/fix/agc-packed-mip-tail-fallback
fix(agc): render into non-resident packed mip tails
2026-10-13 04:50:40 +13:00
Dean 82b1b2e7a4
Merge pull request #4445 from LeandroLP23/fix/agc-library-modules-after-prebuild
fix(agc): keep shader modules of pipeline library parts alive for background linking
2026-10-13 04:50:18 +13:00
MiniRML bf6a054c52 fix(nid): preserve Unicode paths on Windows 2026-10-12 08:43:02 -07:00
MiniRML b4d7a3b6c9 fix(kernel): parse JSON numbers independently of host locale 2026-10-12 08:34:20 -07:00
Xabilimon1 aa88949e2e fix(libkernel): build the fcntl status flags and the getrlimit test on macOS
InitialEntry reads O_DIRECT from the host status flags, and macOS has
no O_DIRECT, so libkernel did not compile there. It is now read only
where the host defines it. GuestGetrlimit iterates over braced lists
without including <initializer_list>, which libc++ requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:33:37 +02:00
Nixitov f1810c89ea feat(libc): implement nearbyintl
OutRun2006 (PPSA99106) imports nearbyintl and stops at start-up on main. Add the long double round-to-nearest-integer export next to nearbyintf; std::nearbyint rounds under the current direction and raises no inexact exception.
2026-10-12 17:29:41 +02:00
MiniRML ca67860168 fix(nid): validate buffer ranges and string terminators 2026-10-12 08:28:52 -07:00
poonasor 08824f3b90 feat(libkernel): implement sceKernelGetModuleList2 and sceKernelGetModuleInfo2
The title-module variants of sceKernelGetModuleList and
sceKernelGetModuleInfo, following shadPS4: the list leaves out system
libraries and the info call answers EPERM for one. A system library is
a loaded .prx image that is not a relinked title module.

NHL 27 (PPSA34063) imports both and fails to load without them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:15:26 -04:00
AlxcBTW 4309bffdb0 fix(agc): take the dword pattern-fill kernel only through a 32-bit output format
The kernel #2081 matches stores each pattern dword with
buffer_store_format_x, so what lands in memory depends on the output
descriptor's FORMAT (bits 12-18 of user[3]). Only 32_UINT, 32_SINT and
32_FLOAT (20-22) store the dword unchanged. Other formats convert it,
and an 8- or 16-bit one writes 1 or 2 bytes of every 4-byte element, so
a buffer fill would also overwrite the bytes in between. Such a dispatch
now goes to the recompiler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:09:31 +02:00
thuanquang 4feeef6981 test(tools): create hard links with os.link for Python 3.9
Path.hardlink_to was added in Python 3.10, so import_audit and stubgen
errored on Python 3.9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:05:04 +07:00
AlxcBTW 676622fd78 fix(shader): count only id operands as uses when dropping specialization debris
referencedIds() took every operand word of every instruction as a
possible id, so a literal that happened to equal the id of a dead folded
constant or an unreachable block kept it: the OpTypeInt width 32 kept a
dead constant %32, LocalSize literals kept dead labels.

Visit only the <id> operands of each instruction. Literal operands are
skipped for the instructions that carry them: type widths, counts and
image parameters, constant values, storage classes, memory access and
image operand masks (their trailing ids still count), composite and
shuffle indices, OpArrayLength members, extended instruction numbers,
entry point names, execution modes, merge and function controls, branch
weights, OpSwitch case values (two words for a 64-bit selector) and
group operations. An instruction without a listed layout still counts
every word, so an unknown instruction can only keep debris, never drop
something in use.

The SpirvModule case now also folds a switch whose dead constant has id
32 and whose dead blocks' ids appear as LocalSize literals; it fails
without this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:03:08 +02:00
Claude ef09cda468
fix(libc): sort with FreeBSD 11's qsort so equal elements keep its order
qsort was a heapsort. It sorted correctly, but elements that compare
equal ended in a different order from FreeBSD's Bentley-McIlroy qsort,
in 18947 of 20000 random arrays with repeated keys, and below 7
elements, where FreeBSD's insertion sort keeps equal elements in
place, a heapsort does not. qsort now follows FreeBSD 11 qsort.c,
including its comparator call sequence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-12 15:01:35 +00:00
AlxcBTW 63ddeb09f4 test(agc): keep the retire test's mock device out of the Linux import probe
On Linux with write watching (uffd write-protect), the first import asks the device whether a GPU
write clears the protection (ProbeImportWriteProtection): it records a vkCmdCopyBuffer and a
vkCmdFillBuffer on the import and submits them. The test's mock device records no commands, so
agc_host_import_retire failed with "missing Vulkan function: vkCmdCopyBuffer" before it reached
the retire (RADV, reported on #4515). The test now sets APS5_WRITE_WATCH_IMPORTS=unwatch, so its
imports are compared as on Windows and the probe, which a mock cannot answer, does not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:00:45 +02:00
saxopa d0502b449d fix(relinker): load a PT_SCE_RELRO segment that no PT_LOAD covers
PS4 executables keep their relocated read-only data, GOT and init/fini
arrays in a PT_SCE_RELRO segment outside every PT_LOAD. The segment filter
dropped it, so Windows and macOS output stopped at the first relocation
into it, and Linux output placed the relinker's extra block over its
addresses without an error. The ELF reader now reports such a segment as a
read-write PT_LOAD. A PT_SCE_RELRO inside a PT_LOAD keeps being skipped,
and one that partially overlaps a PT_LOAD throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:54:13 +02:00
Ori Shamir fc0d46ba00 fix(libkernel): throw instead of aborting when there is no host standard error to keep
A Windows GUI build started without standard handles has no descriptor 2.
_dup(2) then reached the invalid-parameter handler, which aborts, before the
"cannot keep the host standard error" error could be thrown. It now goes
through WithoutParameterHandler like the other descriptor calls in this file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:53:41 +03:00
Scott Schuster 2585eeb7ee fix(libkernel): keep sceKernelDebugOutText off a redirected guest stderr
Guest descriptors are host descriptors, so a guest that moves standard
error with dup2 also moves the stream sceKernelDebugOutText writes to. A
title that forwards its standard error to the kernel log through a pipe
then reads its own debug output back and logs it again without end. Before
the guest's first dup2 onto descriptor 2, the host's standard error is kept,
and sceKernelDebugOutText writes there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:53:41 +03:00
Dean d592d54e11
Merge pull request #2802 from ThatsLeo/perf/agc-untracked-compare-memo
perf(agc): memoize untracked texture comparisons by the stores that reach the surface
2026-10-13 03:42:27 +13:00
Dean 8751a29407
Merge pull request #4150 from eljackjoestar-cmd/codex/ancillary-relative-ssa
fix(shader): preserve ancillary proofs across relative VGPR accesses
2026-10-13 03:42:06 +13:00
Dean f95619b8d2
Merge pull request #4108 from GustavoGamarra95/feat/agc-host-memory-fallback
feat(agc): place textures and storage images in host memory when device memory runs out
2026-10-13 03:41:44 +13:00
Dean acb13d1b39
Merge pull request #4030 from AlxcBTW/fix/recompiler-flat-p10-provoking-v2-2
fix(recompiler): read P10 of a flat input as the provoking vertex
2026-10-13 03:41:23 +13:00
krishnaraya bb028203db test(agc): skip the f32 dot2 rounding test on devices without shaderFloat64
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 10:32:54 -04:00
Nahuel Genchi 22d1fbbc73 fix(libc): throw bad_alloc from operator new when the default heap rejects a size 2026-10-12 11:32:47 -03:00
Simone bdf003a5e8 test(relinker): register weak_imports next to elf_header
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:31:10 +02:00
Kikoarl 94f06cee6f feat(libSceSysmodule): register libSceAcm (0x10B) and libScePsml (0x137) module IDs 2026-10-12 16:22:34 +02:00
Dean 8fa5cc4866
Merge pull request #3995 from delarun/fix/ngs2-dead-cells
feat(libSceNgs2): implement the Geom reset functions
2026-10-13 03:08:54 +13:00
Dean 052134100e
Merge pull request #3869 from gookie-dev/feat/http2-delete-cookie-box
feat(libSceHttp2): implement sceHttp2DeleteCookieBox
2026-10-13 03:08:32 +13:00
Dean fe66af13ef
Merge pull request #4038 from santhoshkumar-dev/fix/libkernel-symlink-file-size
fix(libkernel): report the target size of symbolic links on Windows
2026-10-13 03:08:09 +13:00
Dean 858f75dbee
Merge pull request #3725 from Recapi/carry/screamm-sinhf-asinl
feat(libc): implement sinhf and asinl (carried from #3519)
2026-10-13 03:07:47 +13:00
Dean cee0290c2c
Merge pull request #4331 from oneandonlydean/up4/fix-3504-shader-prep-time
fix(shader): prove masked lanes unread for every select in one backward pass
2026-10-13 03:07:16 +13:00
AlxcBTW 803a131275 fix(shader): store unaligned 32-bit BDA writes byte by byte
EmitBdaWrite, used for buffer stores through GPU-selected descriptors, recorded an
Unaligned fault and dropped every 32-bit store whose address is not 4-byte aligned.
EmitBdaStore and the BDA reads already take the byte path for unaligned addresses, and
raw buffer accesses use the exact bytes, as RDNA does in unaligned mode. The unaligned
case now stores the four bytes one by one like the 8- and 16-bit stores of the same
function.

Sword of the Sea hit this about once per frame from one compute store, so four bytes
were lost and a fault was reported each time.

The BDA store execution table now also runs through EmitBdaWrite; its unaligned dword
cases failed before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:06:16 +02:00
Ondra97 bd842bc7d2 fix(libs): share Windows flock state between duplicated descriptors 2026-10-12 16:03:47 +02:00
Simone cb1c18d552 fix(relinker): keep weak undefined imports weak
Weak undefined imports in the input ELF became STB_GLOBAL in the relinked
output, so a title that weak-imports a function no module exports stopped
at startup instead of binding the import to null.

Keep STB_WEAK on the relinked dynamic symbols. On Windows, write 0 plus
the addend to the slot of a weak import that no searched module exports.

Fixes #4497

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:48:50 +02:00
Reagan Little 74392900d5 fix(libc): unwind guest exceptions through Windows DLL frames
The Windows unwinder stopped at the first frame of a module without the
project's .ehmeta or .ehfram tables, so an exception could not cross
libstdc++-6.dll and libwinpthread-1.dll (std::call_once through
pthread_once) or system DLLs. For such a frame it now looks up the
function's PE unwind data with RtlLookupFunctionEntry and takes the
caller's registers, including the nonvolatile rsi, rdi and xmm6-xmm15,
from RtlVirtualUnwind. A frame whose unwind data has an exception or
termination handler still stops the walk, since those handlers are not
run.

windows_exceptions gets back the std::call_once case of #1423.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:42:51 -04:00
fma-rc 8dcb4e5c6b
docs: mark the run fields of the bring-up form as a first report 2026-10-12 15:41:21 +02:00
Yunus Shaikh 12ef40e4f1 fix(savedata): let a trailing % in a directory name pattern match nothing
sceSaveDataDirNameSearch reads % in the directory name pattern as any
run of characters and _ as one character. The matcher stopped when the
name ran out and then required the pattern to have ended too, so a
trailing % with nothing left to match failed: SAVEDATA% did not find a
save named SAVEDATA, and TRAI_% did not find TRAIL. A % now matches no
characters at the end of a name as it already did in the middle.
2026-10-12 06:37:37 -07:00
Simon 0cd3f63803
Merge branch 'boykopovar:main' into fix/pad-input-persistent-sequence 2026-10-12 15:37:34 +02:00
Dean c6efe068a1
Merge pull request #4253 from codingreapermaps/fix/libkernel-sys-windows-readlink
fix(libkernel_sys): read relative symbolic links on Windows
2026-10-13 02:35:50 +13:00
Dean f1514adea3
Merge pull request #4060 from coltken95/claude/sleepy-dirac-e44kw4
fix(relinker): decode 3DNow! instructions with their ModRM and opcode…
2026-10-13 02:35:21 +13:00
Dean 3b83f71e0f
Merge pull request #3905 from aureau/aureau/carry-libc-strtod-no-conversion-zero
fix(libc): return positive zero when float parsing consumes no input
2026-10-13 02:34:59 +13:00
Dean b39b78a5ad
Merge pull request #3809 from aayushmishraaa/fix/relinker-reject-non-x86-64
fix(relinker): reject input executables that are not x86-64
2026-10-13 02:34:37 +13:00
Dean ddc713fbcf
Merge pull request #4004 from zmeizy/claude/mutex-timedlock-try-first
fix(libkernel): try the lock before checking the pthread_mutex_timedl…
2026-10-13 02:34:16 +13:00
Dean f4b395e28e
Merge pull request #3971 from arreina/fix/param-json-nesting
fix(libkernel): limit param.json nesting depth
2026-10-13 02:33:55 +13:00
Dean 1fb5635077
Merge pull request #3967 from MarcZX100/codex/carry-sjlj-mingw-guard
fix(build): reject MinGW compilers that select SjLj exceptions
2026-10-13 02:33:33 +13:00
Dean fefecc61c2
Merge pull request #3954 from MarcZX100/codex/carry-clock-error
fix(libkernel): return SCE errors when clock calls fail
2026-10-13 02:33:12 +13:00
Dean 9a01496582
Merge pull request #3939 from zaydzaari/research/rtc-named-zones-1342
fix(rtc): recognize additional measured named time zones
2026-10-13 02:32:51 +13:00
Dean 57dc136026
Merge pull request #3936 from MarcZX100/codex/carry-fopen-s-output-null
fix(libc): clear fopen_s output on invalid arguments
2026-10-13 02:32:30 +13:00
Dean 993f80a081
Merge pull request #3912 from GalaxyGamingFR/fix/pr-overlap-wrapped-exports
fix(tools): ignore wrapped declarations in pr_overlap exports
2026-10-13 02:31:59 +13:00
Dean 11c9522cf9
Merge pull request #3893 from MarcZX100/codex/carry-credential-setters-3862
feat(libkernel): export credential setters and supplementary groups
2026-10-13 02:31:36 +13:00
Dean a1a9c3db59
Merge pull request #3860 from excited-raccoon/perf/relinker-linear-control-flow
perf(relinker): walk fallthrough instructions without queueing
2026-10-13 02:31:15 +13:00
SibteProf c0967216bf fix(relinker): recognize SDK memory syscall trap patterns 2026-10-12 18:25:06 +05:00
Karan Vora 69d0dc2288 perf(shader): treat f32 min, max, med3, floor and ceil results as denormal-free
In the float modes that flush f32 denormals, writeOperand flushes the result
of v_min/max/min3/max3/med3_f32 and v_floor/ceil_f32. DenormalFlushEliminator
drops a flush only when it can show the value isn't a denormal, and it had
no rule for these opcodes, so their result flush stayed even when every
operand had already been flushed.

FPMin32, FPMax32, FPMinTri32, FPMaxTri32 and FPMedTri32 return one of their
operands' bits, or the and or or of two zeros, so the result is denormal-free
when every operand is. FPFloor32 and FPCeil32 return an integer, a zero, an
infinity or a NaN whatever their operand. In IEEE mode the min and max
results and the floor and ceil results go through selects with a quieted
operand, which the eliminator can't follow, so their flush stays there.

agc_denormal_flush_elimination covers the five min and max forms with
flushed and with unknown operands, floor and ceil of an unknown value, and a
max carried around a loop.
2026-10-12 09:24:29 -04:00
Simon 70481b0703 fix(pad-input): preserve command ordering across clock resets 2026-10-12 15:23:22 +02:00
fma-rc b6f81995fc
docs: add a discussion form for game bring-up threads 2026-10-12 15:23:16 +02:00
Evgeniy Kazarin 33c955a8e3 perf(relinker): index guest exports for dependency resolution 2026-10-12 16:15:06 +03:00
Abdullah 7e2832475f fix(libc): return stream errors from fwrite, fread and fputs instead of throwing 2026-10-12 16:14:25 +03:00
Alex Collini ff3eae6c9a feat(agc): sample non-sRGB textures through FORCE_DEGAMMA samplers as sRGB views
A sampler with FORCE_DEGAMMA decodes the texels of a non-sRGB 8-bit texture
as sRGB. Such a binding was refused; it now samples an sRGB view of the same
image. Snapshot images whose format has an sRGB twin (R8, R8G8, RGBA8, BGRA8,
ABGR8 packed, BC1/2/3/7 UNORM) are created with MUTABLE_FORMAT, and storage
images are already mutable. The view is made on first use for the full,
first-layer or base-level range, with sampled usage only and the descriptor's
minimum LOD. A format without an sRGB twin is still refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:11:34 +02:00
winstrex a47178b86f fix(libkernel): open directories whose host path ends in a separator on Windows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:06:44 -03:00
fablevoid 1541244b78 fix(relinker): treat jump table targets as branch targets when moving instructions
The AMD-only converter moves the instructions next to a short AMD-only
instruction into its stub, and refuses to move one that a branch
enters. It knew only direct jump and call targets, so a switch case
entered through a jump table could land inside the jump written over
the moved instructions.

The converter now also reads relative jump tables: a RIP-relative LEA
whose address lies in a loaded segment starts a table of 32-bit
offsets from that address, read while each target starts an
instruction of the segment being converted. To read them, Convert
takes the program headers and converts their executable load
segments; the relinker passes all headers, and
ElfReader::ReadCodeSegments, now unused, is removed.

The converter test builds a dispatch through such a table whose second
case enters the instruction after a 4-byte 256-bit store, and checks
that the store takes the instruction before it instead. It also checks
that reading stops at an entry that does not start an instruction,
that only a LEA forms a table address, that tables are read only
inside loaded segments, that only executable load segments are
converted, and that a segment past the end of the file fails the
conversion.

PPSA12544: one 256-bit store in Il2cppUserAssemblies moved the
instruction after it, which is case 1 of a switch; it now goes through
an island. The other relinked files are unchanged.

AI-assisted: yes
2026-10-12 13:06:23 +00:00
Dean 33ae282e4e
Merge pull request #4325 from gravelas/feat/shader-replay-prepare
feat(agc-driver): replay a request as a prepared artifact with --prepare
2026-10-13 01:57:48 +13:00
Dean 9bc4356990
Merge pull request #4295 from AaravMehta-07/codex/kernel-socket-address-length
fix(libkernel): report copied socket address lengths
2026-10-13 01:57:25 +13:00
Dean 58ee7af7ae
Merge pull request #4231 from MarcZX100/codex/carry-gai-strerror-4055
fix(libScePosixForWebKit): match FreeBSD gai_strerror text
2026-10-13 01:57:10 +13:00
jweidenh b00bd9fa11 test(agc): skip import retirement without compatible host imports 2026-10-12 14:56:47 +02:00
Dean f4b47ee51f
Merge pull request #4014 from ahir061/fix/macos-executable-directory
fix(libs): find the executable directory on macOS
2026-10-13 01:56:47 +13:00
jweidenh 408fa9cbf5 fix(agc): defer host import retirement until the GPU lock is held 2026-10-12 14:56:47 +02:00
jweidenh c4faf55fc4 test(agc): cover unlocked host import retirement during mapping 2026-10-12 14:56:47 +02:00
Dean 4bf963d660
Merge pull request #3966 from MarcZX100/codex/carry-strcasecmp-lowered
fix(libc): compare strcasecmp results after lowercasing bytes
2026-10-13 01:56:24 +13:00
arcwiser 441d392c35 fix(tools): batch pr_overlap fetch refspecs 2026-10-12 23:53:47 +11:00
overlordxrz-source 0bcff53b2c fix(recompiler): run vertex programs as one-lane waves without vertex subgroups
lavapipe and MoltenVK leave the vertex stage out of subgroupSupportedStages,
so the driver's shader validation refuses every vertex program that declares
GroupNonUniform ("subgroup capability 61 is unsupported for shader stage 1").
Most do, since the entry EXEC is a ballot.

The device target now records whether the vertex stage has subgroups. When
it does not, vertex and local programs get a host subgroup width of 1: s3
reports one vertex and one primitive, the lane id is 0, a ballot is the
invocation's own bit, a shuffle returns the invocation's value, an elect is
true and a half-wave reduction read is the key itself. Reads of other lanes
keep the existing narrow-host rules and throw where they did. Devices with
vertex subgroups emit the same SPIR-V as before.
2026-10-12 08:50:05 -04:00
Gustavo Ariel Gamarra Rojas d56b22541a perf(agc): wait once per unit run when a storage image captures its guest bytes 2026-10-12 09:36:54 -03:00
Gustavo Ariel Gamarra Rojas f16a860227 feat(agc): read committed guest memory without the flush hook 2026-10-12 09:36:54 -03:00
ThatsLeo ca99658cef perf(agc): memoize untracked texture comparisons by the stores that reach the surface
The memo stamp held TrackerGeneration, which every collect and driver store
advances, so it almost never matched. Driver stores into uncovered ranges
record their generation per 64 KiB block, and NewestStamp of the surface
replaces TrackerGeneration in the stamp.
2026-10-12 14:34:14 +02:00
marcio-ch 3bc3e35a02 fix(agc): handle the fill kernel that reads its pattern from a buffer
The 16-byte fill kernel has a variant that loads its pattern with
s_buffer_load_dwordx4 through the V# in s[4:7] instead of taking it from
the user SGPRs. Vampire Crawlers (PPSA30703) clears its UI canvas HTILE
with it every frame; run as a shader, the depth surface never cleared and
every UI draw failed its GEQUAL depth test, leaving the screen black.
2026-10-12 09:32:17 -03:00
Hannah Lyons 4e3aa159d9 feat(libkernel): export sceKernelGetMainSocId, sceKernelGetCpumode and sceKernelGetCpuFrequency 2026-10-12 08:32:16 -04:00
Dean 0ef9dc9282
Merge pull request #4277 from BharatYadav007/bharat/libc-mktime-negative-one
fix(libc): normalize valid mktime minus-one results
2026-10-13 01:30:26 +13:00
Dean d58ba1010e
Merge pull request #4232 from MarcZX100/codex/carry-fdopen-modes-4022
fix(libc): accept FreeBSD fdopen modes
2026-10-13 01:30:04 +13:00
Dean 71c3dbb722
Merge pull request #4190 from ArchitDewan/fix/relinker-empty-path
fix(relinker): reject empty positional paths
2026-10-13 01:29:30 +13:00
Dean e50326224c
Merge pull request #4103 from yunusshaikh7/fix/libc-difftime-negative-times-windows
fix(libc): subtract negative times in difftime on Windows
2026-10-13 01:29:12 +13:00
Dean 90c7ab3390
Merge pull request #4102 from itsbo5/fix/libkernel-udp-send-edestaddrreq
fix(libkernel): return EDESTADDRREQ for send and sendto on unconnecte…
2026-10-13 01:28:39 +13:00
Dean 256cc9f976
Merge pull request #4099 from yunusshaikh7/fix/libc-asctime-years-before-1900-windows
fix(libc): format years before 1900 in asctime on Windows
2026-10-13 01:28:18 +13:00
Dean 104bb65c94
Merge pull request #4093 from kallmek3nny/fix/aio-precise-poll-sleep
fix(aio): use precise polling sleep
2026-10-13 01:27:47 +13:00
Dean f8dee05957
Merge pull request #4091 from jweidenh/codex/guest-noop-relocations
fix(relinker): ignore no-op relocations in guest modules
2026-10-13 01:27:26 +13:00
Dean 253ec3ffee
Merge pull request #4084 from hawwwwwk/pr/relinker-suprx-guest-alias-current
fix(relinker): resolve .suprx guest module aliases
2026-10-13 01:27:08 +13:00
Dean c5675762a2
Merge pull request #4069 from Kikoarl/feat/sysmodule-voicechat-module-id
feat(libSceSysmodule): register libSceVoiceChat module ID (0x114)
2026-10-13 01:26:25 +13:00
screamm 23ac439214 feat(libc): implement __umodti3
Kart PS5 (PPSA99611, Phi1ow/mkwii-ps5 v1.0.0-rc1) stops on it right
after __divti3. The related open PR #4037 reports: "with this change it
passes `__divti3` and stops at `ELSr5qm4K1M` (`__umodti3`)".
PS5CEMU-HAR (PPSA99360) imports it too: tools/import_audit.py lists
ELSr5qm4K1M __umodti3 as absent from libSceLibcInternal.prx (registry
index 359), so the predicted stop is
"FAIL: unresolved ELF import ELSr5qm4K1M from libSceLibcInternal.prx".
libSceLibcInternal imports fall back to libc.prx, so the export lives in
libc beside __udivti3. compute_nid and aerolib (zecoxao/sce_symbols
2883963a) both give ELSr5qm4K1M = __umodti3.

__umodti3 is compiler-rt's lib/builtins/umodti3.c (llvm-project
0ee439b705e82a4fe20e266bc8fea96d0e60e1ec): the remainder that
__udivmodti4 leaves. The restoring division of SonyUdivti3 already
computes it, so the loop moves to SonyUdivmod128 and both helpers use
it. A zero divisor reaches a 64-bit divide in __udivmodti4 and traps on
x86-64; this throws instead, as __udivti3 does, and names the dividend.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 12:26:15 +00:00
Dean a46ffb5e75
Merge pull request #4066 from hawwwwwk/pr/relinker-ff-callsite-current
fix(relinker): filter non-reference RIP-relative FF operations
2026-10-13 01:25:57 +13:00
Dean fb23e85f66
Merge pull request #4063 from MarcZX100/codex/carry-pthread-join-self-4052
fix(libkernel): return EDEADLK for self-join and EINVAL for null threads
2026-10-13 01:25:36 +13:00
Ori Shamir 1205d03daa fix(relinker): resolve relocations against null symbol entries to 0
A relocation whose dynamic symbol entry is all zero, like the null symbol,
now takes the value 0 plus its addend, as the gABI defines for STN_UNDEF.
The Linux output imports such an entry as an unnamed weak symbol, which the
host loader resolves to 0. The Windows and macOS outputs write the value
into the slot instead of failing with "Empty import symbol name". Such
references are left out of the call registry. An unnamed symbol entry that
is not all zero still fails the relink.

OliSe Player (PPSA01153) has seven of these entries and calls through the
slots only when they are not 0 (#4437).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:24:56 +03:00
Dean 029c1bc17d
Merge pull request #3926 from MarcZX100/codex/carry-fclose-error
fix(libc): return fclose failures to callers
2026-10-13 01:24:43 +13:00
Dean 906ce3f20c
Merge pull request #3599 from CouchRiv/fix-libc-exp2-errno
fix(libc): exp2 leaves errno unchanged
2026-10-13 01:24:15 +13:00
Dean 6ee0720ded
Merge pull request #4311 from leorossi2005/feat/libkernel-cpu-temperature
feat(libkernel): implement sceKernelGetCpuTemperature
2026-10-13 01:24:01 +13:00
Dean df055db921
Merge pull request #4256 from MarcZX100/codex/fix-avplayer-test-unwind-2709
test(avplayer): link guest_avplayer with the shared runtime libraries
2026-10-13 01:23:34 +13:00
Dean 9b20dd58c0
Merge pull request #4251 from Dextroid17/fix/libampr-usage-stats-stubs
fix(libSceAmpr): export sceAmprAmmSetPageTablePoolOccupancyNotificationThreshold
2026-10-13 01:23:06 +13:00
Dean c99cc11cf5
Merge pull request #4194 from fable-void/pr/rosetta-store-split
feat(relinker): split unaligned 256-bit stores for Rosetta
2026-10-13 01:22:45 +13:00
Dean a951cef8f4
Merge pull request #4272 from Ondra97/codex/socket-receive-host-write
fix(libs): allow socket receives into watched guest memory
2026-10-13 01:22:17 +13:00
Dean a88c4f272f
Merge pull request #4234 from solbjorg1245/upstream/savedata-search-info
fix(savedata): fill the search infos of sceSaveDataDirNameSearch
2026-10-13 01:21:48 +13:00
Dean 4d5fcef15b
Merge pull request #4203 from saxopa/fix/relinker-relative-section-symbol
fix(relinker): accept RELATIVE relocations against a zero-value section symbol
2026-10-13 01:21:34 +13:00
Dean 9a1922145d
Merge pull request #4080 from hugodearaujo/fix/rwlock-destroy-held
fix(libkernel): destroy rwlocks the way the console does
2026-10-13 01:21:08 +13:00
Dean ed14cb4e0a
Merge pull request #4053 from nikowolf123/fix/libkernel-close-guest-sockets
fix(libkernel): close guest sockets in sceKernelClose
2026-10-13 01:20:47 +13:00
Dean baee04e810
Merge pull request #4037 from Nixitov/feat/libc-divti3
feat(libc): implement __divti3
2026-10-13 01:20:26 +13:00
Gustavo Ariel Gamarra Rojas b35117c285 fix(agc): choose host memory from the heap budget instead of retrying
Read the device-local heap's VK_EXT_memory_budget figures before a texture
or storage image allocation and pick a host memory type when the
allocation does not fit, rather than allocating again after the driver
refused the first attempt. The allocation itself is made once and still
throws when it fails.
2026-10-12 09:13:34 -03:00
Gustavo Ariel Gamarra Rojas 85929389b5 test(agc): cover the host memory fallback of device allocations 2026-10-12 09:13:34 -03:00
Gustavo Ariel Gamarra Rojas eb03e0e154 feat(agc): place storage images in host memory when device memory runs out 2026-10-12 09:13:34 -03:00
Gustavo Ariel Gamarra Rojas 61180981ce feat(agc): place textures in host memory when device memory runs out 2026-10-12 09:13:34 -03:00
AlxcBTW eaf5ca240f fix(agc): read a parked import through its holder's map node
RetiredImport now owns the dropped import's map node (std::map::extract), so releaseParkedImports
takes the parked import's range from node.mapped().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:11:35 +02:00
AlxcBTW c54fb9d522 Merge remote-tracking branch 'origin/main' into fix/host-import-retire-hold 2026-10-12 14:08:34 +02:00
SibteProf 5ffafa920f fix(libc): reject oversized secure copy destinations 2026-10-12 17:06:54 +05:00
Dean ffa198407e
Merge pull request #3765 from pushkarreddyy/feat/libkernel-wait-rlimits
feat(libkernel): answer getrlimit for FreeBSD resources
2026-10-13 00:44:48 +13:00
Dean 2dfde65fa1
Merge pull request #3789 from xXPBSXx/fix/agc-workload-nop-packets
fix(libSceAgc): emit NOP packets for the DCB workload calls
2026-10-13 00:44:27 +13:00
Dean ac2ad045fc
Merge pull request #1357 from TibixDev/pr/shared-import-spans
fix(agc): retry failed host imports after range replacement
2026-10-13 00:43:28 +13:00
Dean 7300101fa2
Merge pull request #3700 from pushkarreddyy/feat/libkernel-sysctl-kern-arandom
feat(libkernel): support MIB 1.37 (kern.arandom) in sysctl
2026-10-13 00:43:14 +13:00
Del'aRun cac398cb96 feat(libSceNgs2): implement the Geom reset functions
Implement sceNgs2GeomResetListenerParam and sceNgs2GeomResetSourceParam,
taken from #1021 and limited to the two reset functions. The Geom
structures get their real layouts. sceNgs2GeomCalcListener and
sceNgs2GeomApply stay unimplemented.

Co-Authored-By: Dextroid17 <217507631+Dextroid17@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:39:27 +04:00
LeandroLP23 2919dd38cb fix(agc): keep shader modules of pipeline library parts alive for background linking
#4152 dropped the device-wide module list that #3173 added, so Pipeline
destroys the shader modules right after the library parts are created, also
for the parts prebuilt at registration. AMD's Windows driver still reads
them during the background link-time-optimized link and faults inside
amdvlk64.dll. Hand the modules of each new part to the device's library
store again and destroy them in ClearPipelineLibraries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:14:02 +02:00
Dean 3d8ffeb271
Merge pull request #4395 from oneandonlydean/up4/carry-1810
fix(agc): cache Linux describePages results
2026-10-12 23:54:52 +13:00
Dean 8eee5cfad5
Merge pull request #4118 from Mouad-Scriptz-0/feat/npauth-authorized-app-dialog
feat(libSceNpAuthAuthorizedAppDialog): add the dialog, with NpAuth and SaveData imports of Minecraft
2026-10-12 23:54:30 +13:00
Dean 0e61bedf9a
Merge pull request #4162 from Celegans12/fix/shader-wave64-lane-reductions
fix(shader): match half-wave reductions over relatively addressed vector registers
2026-10-12 23:54:08 +13:00
Dean 3356c28fd6
Merge pull request #4106 from fma-rc/feat/agc-present-mode
feat(agc): select the swapchain present mode with ANYPS5_PRESENT_MODE
2026-10-12 23:53:46 +13:00
Dean 5f3b94cb19
Merge pull request #3840 from ahir061/feat/libkernel-fcntl-files
feat(libkernel): support fcntl and ioctl on non-socket descriptors
2026-10-12 23:53:24 +13:00
Dean 5a031d49e8
Merge pull request #4324 from abhinav29102005/feat/libkernel-memory-pool-commit-type
fix(libkernel): propagate memory type in sceKernelMemoryPoolCommit and batch commit
2026-10-12 23:53:02 +13:00
Dean 090e26aac1
Merge pull request #4291 from diversao/fix/agc-release-parked-imports
fix(agc): release parked host imports a pinned guest range waits for
2026-10-12 23:52:40 +13:00
Dean dfb2033eb1
Merge pull request #3889 from devavijitsingh/fix/agc-write-tracker-lifetime
fix(agc): keep write tracker alive through driver teardown
2026-10-12 23:52:18 +13:00
Dean 9fca13b538
Merge pull request #4009 from dantdmdarealguy/feat/input-deadzone-sensitivity
feat(input): configure stick deadzones and mouse sensitivity
2026-10-12 23:51:54 +13:00
Dean b6aa03eae1
Merge pull request #3956 from GustavoGamarra95/feat/agc-storage-dump-selector
feat(agc): select storage dumps by shape and store them at each flip
2026-10-12 23:51:32 +13:00
Dean b40a0b17dc
Merge pull request #3946 from danzaio/fix/shader-failure-address
fix(agc): name the shader address and stage in preparation failures
2026-10-12 23:51:09 +13:00
Dean c390d81552
Merge pull request #4326 from winstrex/feat/libkernel-sceKernelEnableDmemAliasing
feat(libkernel): implement sceKernelEnableDmemAliasing
2026-10-12 23:50:39 +13:00
Dean 98341494df
Merge pull request #4308 from utkuhalis/pr/agc-acb-rendering-wait
feat(libSceAgc): implement sceAgcAcbWaitUntilSafeForRendering
2026-10-12 23:50:06 +13:00
Dean 7cb5238d53
Merge pull request #4281 from eljackjoestar-cmd/codex/reserve-direct-memory
perf(libkernel): commit Windows direct backing when mapped
2026-10-12 23:49:42 +13:00
Dean b117e31f39
Merge pull request #4186 from Scramblrrrr/codex/host-hole-query-cross-test
fix(memory): exclude arena host holes from every write-tracking query
2026-10-12 23:49:18 +13:00
Dean e9d35d6491
Merge pull request #3636 from JAB-dev/feat/agc-color-target-1-5-5-5
feat(agc): render 1_5_5_5 UNORM color targets
2026-10-12 23:48:42 +13:00
Dean 31839d413c
Merge pull request #4316 from gravelas/fix/agc-far-out-of-range-indices
fix(agc-driver): move indices far past every vertex fetch’s records to the first zero vertex
2026-10-12 23:48:23 +13:00
Dean c1d59a1125
Merge pull request #4245 from AchrafReyani/fix/agc-linear-2d-texture-default-pitch
fix(agc): accept a linear 2D texture whose DEPTH holds its default pitch
2026-10-12 23:48:00 +13:00
Dean 52973f89db
Merge pull request #4076 from Nesyth/fix/agc-cb-metadata-pass-without-depth-planes
fix(agc): accept a CB metadata pass beside depth state without depth or stencil planes
2026-10-12 23:47:38 +13:00
Dean f55e1117d4
Merge pull request #4058 from ee6aba54/fix/videoout-event-unopened-port
fix(libSceVideoOut): return INVALID_HANDLE for events on ports that are not open
2026-10-12 23:47:16 +13:00
Dean eee8541dae
Merge pull request #2904 from Scramblrrrr/codex/depth-storage-reuse
fix(graphics): allow storage textures in reused depth memory
2026-10-12 23:46:54 +13:00
Dean c3204078e4
Merge pull request #4270 from ErenYeager1836/fix/shm-unlink-windows-return
fix(libkernel): return after NotImplemented in Windows shm_unlink
2026-10-12 23:46:32 +13:00
AlxcBTW bb1325938e test(agc): compare the cost of more formatted loads with the first one, not with the module
agc_formatted_buffer_once required two more formatted loads from a known
descriptor to add less than a tenth of the module. The module was mostly
what specialization left of the folded format switch. Without those
leftovers it has 1,219 words and the two call sites add 225, so the
ratio failed while nothing was duplicated.

Require the two extra loads to add fewer words than the first one,
which also brings the shared function. A second copy of that function
per load still fails this check, as well as the function count checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 12:46:16 +02:00
lorkydey 86ce78c633 fix(tools): reject invalid NIDs in the name lookup CLI 2026-10-12 12:42:48 +02:00
lorkydey 4d29852a25 fix(ci): reject disabled CTest cases in skip validation 2026-10-12 12:39:52 +02:00
Ondra97 ec5688a666 fix(libkernel): bind deferred initialization to the loaded image 2026-10-12 12:34:35 +02:00
gookie ce0915e834 feat(libSceHttp2): implement sceHttp2DeleteCookieBox
PPSA35943 (Graveyard Keeper 2) imports sceHttp2DeleteCookieBox, which no
library exported. On current main the loader stops the title there:

  ./eboot.elf: symbol lookup error: ./eboot.elf: undefined symbol:
  O9ync3F-JVI

sceHttp2DeleteCookieBox(cookieBoxId) erases the box from the handle
registry sceHttp2CreateCookieBox adds it to and returns 0, or the
library's invalid-id error (0x817B1100) for an id that is not a live
cookie box. The signature follows SharpProspero and the behaviour
prosper's sceHttp2DeleteCookieBox; the error code is listed in
TechnicalDebt as not measured on a console.

guest_http2 deletes a box twice, a context id, a box whose context was
terminated, and the two boxes it uses before sceHttp2Term.

With this change the title loads and runs into its asset loading.
2026-10-12 12:24:57 +02:00
AlxcBTW 3ea89674d2 refactor(shader): drop unused folded constants and unreachable blocks after specialization
SpecializeSpirv hoists every instruction it folds into a module-level
constant and keeps that constant after its last use has folded away
too. It also leaves each block that a folded branch cuts off as
OpLabel; OpUnreachable. A formatted buffer helper's 77-case format
switch leaves about 1,800 such blocks.

Emit only the folded constants that something still refers to, and
remove OpLabel; OpUnreachable blocks that no instruction names. Merge
and continue targets of live constructs are named, so they stay.

The specialized modules lose words, not behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 12:17:25 +02:00
eljackjoestar-cmd ae049e7757 fix(shader): restrict ancillary refolding to live builtin uses 2026-10-12 14:09:32 +04:00
john.maia 0b46084c9f fix(agc): build pipeline library shader parts for the draw's depth format
The pre-rasterization and fragment shader libraries were created with an
empty VkPipelineRenderingCreateInfo, so their depth and stencil formats
were VK_FORMAT_UNDEFINED even when the output library had a depth target.
On RADV (RX 7600, Mesa 25.2.8) a fast-linked pipeline built that way hangs
the GPU at its first draw: Epic Mickey loses the device as soon as the
level renders its translucency lighting volume, and with
APS5_NO_PIPELINE_LTO=1 it hangs within seconds of boot. The shader parts
now get the view mask and depth/stencil formats of the draw, and those
formats join their cache key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:09:00 +01:00
muhzain05 48919d01e4 fix(videodec2): answer picture info from the decoder that last wrote the buffer
sceVideodec2GetPictureInfo searched the live decoders in handle order and
returned the first one that had ever written the queried frame buffer. When
two decoders wrote the same address, the lower handle answered with stale
timestamps, a stale AVC decoder answered for an HEVC or VP9 picture, a stale
HEVC or VP9 decoder made an AVC query throw, and resetting or deleting the
decoder that wrote the buffer last exposed the older decoder's picture again.

Record the decoder that last published a picture into each frame buffer and
answer from that decoder only. Reset and Delete drop only the decoder's own
records, so another decoder's picture is never removed or brought back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:06:54 -06:00
Achraf Reyani 69728a0cb0 fix(agc): rasterize a single-sample scan into a multisampled target at the pixel center
With PA_SC_AA_CONFIG at one sample and MSAA_ENABLE off, the hardware scans
each pixel once and gives every sample of a multisampled color target its
result: radeonsi programs exactly this when GL multisampling is disabled on
a multisampled framebuffer (si_emit_msaa_config leaves sc_aa_config 0), and
GL defines it as single-sample rasterization with full coverage. Such a draw
without depth or alpha-to-coverage now rasterizes the target's sample count
with every sample location at the pixel center, which covers all samples
exactly when the center is covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:05:04 +09:00
Aarav 0eec3fd74a test(sce-net): avoid adjacent PR insertion points 2026-10-12 15:30:47 +05:30
Adrià Franch 8ccf9ee752 ci: remind stale conflicting pull requests to rebase
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 11:54:58 +02:00
Adrià e7c70a2df9
Merge pull request #4405 from adriadam10/ci/path-gate-tests
ci(build): run pull request jobs only when their files change
2026-10-12 11:54:45 +02:00
eljackjoestar-cmd b3587f9528 fix(shader): preserve ancillary proofs across relative VGPR accesses 2026-10-12 13:36:30 +04:00
Adrià Franch d9d00f0e34 ci(build): run pull request jobs only when their files change
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 11:35:11 +02:00
Jake Wang 09c0fa5daf fix(shader): release bundled optimizer traversal maps 2026-10-12 05:29:36 -04:00
Dean Galvin 9b91d2f66b fix(libc): round mspace block sizes to the 32-byte alignment 2026-10-12 22:21:01 +13:00
Hannah Lyons d316fcd8d5 feat(libc): export std::overflow_error type info, vtable and destructor 2026-10-12 05:20:17 -04:00
Adrià 9aa5fd2900
Merge pull request #4393 from adriadam10/docs/contributing-title-blockers
docs(contributing): name the title a pull request unblocks
2026-10-12 11:15:35 +02:00
Adrià Franch 7949388c0b docs(contributing): name the title a pull request unblocks
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 11:05:40 +02:00
Onny2 2bb8b83765 test(net): look up the unresolvable name as an absolute name
guest_sce_net expects sceNetResolverStartNtoa and
sceNetResolverStartNtoaMultipleRecordsEx to fail for
guest-sce-net.invalid. The resolver delegates to the host's
getaddrinfo, which retries a name that is not found with the host's
DNS search domains. On an ordinary home network whose router sets a
search domain that answers any name, the lookup then succeeds as
guest-sce-net.invalid.<search domain> and the test aborts.

Use the absolute name guest-sce-net.invalid. so the host applies no
search domain and the lookup fails on any network.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:05:39 +02:00
Mouad-Scriptz-0 295e6b501d feat(libSceNpAuthAuthorizedAppDialog): add the dialog, with NpAuth and SaveData imports of Minecraft
Minecraft (PPSA17221) fails to load on nine absent imports. The authorized-app
dialog runs the common-dialog state machine without UI and reports the user
as having cancelled, like the login and VR setup dialogs. The other two,
sceNpAuthGetAuthorizedAppCode and the unnamed libSceSaveData.native NID
RvID8BVeg+g, are declared as throwing stubs with unknown signatures.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 08:53:30 +00:00
screamm 5f3fb3dddd feat(libc): implement asinl
RetroArch 1.0.0-beta.1 (PPSA99169) stops on main 0f863c10 at

    FAIL: unresolved ELF import Nx-F5v0-qU8 from libSceLibcInternal.prx

Nx-F5v0-qU8 is asinl (tools/nid_names.py, aerolib).

The implementation follows the asinl of the libc.prx bundled with
PPSA28319, read from its disassembly: FreeBSD msun's e_asinl.c with
the ld80 invtrig.c coefficients (9f043204), which the binary holds as
the same 80-bit constants, computed in the x87 long double the guest
uses. +-1 returns +-pi/2 rounded to 64 bits and +-0 keeps its sign.
For |x| > 1, the infinities and NaN, Sony's error helper raises
FE_INVALID and sets errno to EDOM before returning (x - x) / (x - x),
so a NaN argument sets EDOM too.

20 million random arguments in (-1, 1) plus the branch edges give the
same bits as that code from the title's libc.prx run on a Windows
host. guest_math pins a set of those bits and checks the domain
errors' errno and FE_INVALID, and that errno is untouched otherwise.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 10:51:59 +02:00
screamm 2c6e3f53ff feat(libc): implement sinhf
Ruffle Flash 1.2.0 (PPSA68091) stops on main 0f863c10 at

    FAIL: unresolved ELF import 1t1-JoZ0sZQ from libSceLibcInternal.prx

1t1-JoZ0sZQ is sinhf (tools/nid_names.py, aerolib). RetroArch
1.0.0-beta.1 (PPSA99169) imports it as well.

The implementation follows the sinhf of the libc.prx bundled with
PPSA28319, read from its disassembly: FreeBSD msun's e_sinhf.c as of
5aa554c7 (before __ldexp_expf, so expf(|x| / 2) is squared between
logf(FLT_MAX) and the overflow threshold), calling msun stable/9
expm1f and expf (59bc2f09), whose paths for the arguments sinhf passes
are inlined. Past the threshold Sony's error helper sets errno to
ERANGE before returning x * 1e37; NaN and the infinities return x + x
and leave errno alone.

Running that code from the title's libc.prx on a Windows host gives
the same bits as this implementation for every finite argument up to
the threshold, both signs (2,238,032,378 inputs). guest_math pins a
set of those bits, the overflow errno and FE_OVERFLOW, and checks that
errno is untouched otherwise.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 10:51:00 +02:00
ivica00 436e4191c7 fix(shader): decorate rect-list gl_Position as Invariant
The vertex stage already marks Position Invariant, and the rect-list stages have to match that interface.
2026-10-12 10:45:38 +02:00
milescoviello 98f6639e9e fix(net): make new IPv6 sockets IPv6-only as FreeBSD does
On Linux, socket() and sceNetSocket() create AF_INET6 sockets in the
host's default dual-stack mode (net.ipv6.bindv6only is 0), so a wildcard
IPv6 bind also claims the IPv4 port. A title that keeps an IPv4 and an
IPv6 socket on the same port fails: with 0.0.0.0:P bound, binding [::]:P
returns EADDRINUSE (48), and an IPv6 socket bound to [::] also receives
IPv4 traffic from v4-mapped peers.

FreeBSD makes every new IPv6 socket IPv6-only. sys/netinet6/in6_proto.c:

	VNET_DEFINE(int, ip6_v6only) = 1;

sys/netinet/in_pcb.c, in_pcballoc():

	if (INP_SOCKAF(so) == AF_INET6) {
		inp->inp_vflag |= INP_IPV6PROTO;
		if (V_ip6_v6only)
			inp->inp_flags |= IN6P_IPV6_V6ONLY;
	}

and sys/netinet6/in6_pcb.c, in6_pcbbind(), looks for an IPv4 owner of
the port only when the flag is clear:

	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
	    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {

socket() and sceNetSocket() now set IPV6_V6ONLY on every IPv6 socket
they create. Windows already defaults to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 08:44:27 +00:00
Dean c36fd0a0eb
Merge pull request #4321 from oneandonlydean/up4/fix-3308-watch-mapping
perf(libkernel): find direct mappings that share physical memory through an index
2026-10-12 21:43:41 +13:00
Dean a3b3cec05e
Merge pull request #4230 from MarcZX100/codex/carry-socket-flags-4028
fix(libkernel): accept socket type flags
2026-10-12 21:42:57 +13:00
Dean c22e2344ba
Merge pull request #4227 from MarcZX100/codex/carry-mbstowcs-4027
fix(libc): count full string with null mbstowcs destination
2026-10-12 21:42:35 +13:00
Dean 9fdddc8747
Merge pull request #4160 from hugodearaujo/fix/join-self-create-attr
fix(libkernel): join the calling thread and create from an unset attribute as the console does
2026-10-12 21:42:14 +13:00
Dean 82fc98f5e5
Merge pull request #4158 from hugodearaujo/fix/mutex-errors
fix(libkernel): return the console's errors from the SCE mutex calls
2026-10-12 21:41:52 +13:00
Dean 5ccf78e4e3
Merge pull request #4153 from hugodearaujo/fix/pthread-attr-errors
fix(libkernel): return the console's errors from the scePthreadAttr calls
2026-10-12 21:41:31 +13:00
Dean b2cc2df954
Merge pull request #4119 from hugodearaujo/fix/accessibility-defaults
fix(libSceUserService): report the console's default accessibility settings
2026-10-12 21:41:16 +13:00
Dean 7ea2022227
Merge pull request #4104 from hugodearaujo/fix/username-console
fix(libSceUserService): answer sceUserServiceGetUserName as the console does
2026-10-12 21:40:46 +13:00
Dean 69f7411ec9
Merge pull request #4096 from hugodearaujo/fix/solosched-values
fix(libkernel): accept only the solo scheduling values the console accepts
2026-10-12 21:40:24 +13:00
Dean 375e99ec33
Merge pull request #4095 from yunusshaikh7/fix/libc-towctrans-descriptors
fix(libc): map _Towctrans descriptors 1 and 2 to lower and upper case
2026-10-12 21:40:02 +13:00
Dean 49b6b6a5c8
Merge pull request #4092 from yunusshaikh7/fix/libscenet-datagram-receive-timeout
fix(libSceNet): report EAGAIN when a datagram receive times out on Windows
2026-10-12 21:39:40 +13:00
Dean 9b152c43d0
Merge pull request #4090 from yunusshaikh7/fix/libc-fopen-delete-sharing-windows
fix(libc): open fopen streams with delete sharing on Windows
2026-10-12 21:39:18 +13:00
Dean 10aff1c663
Merge pull request #4077 from hugodearaujo/fix/sched-priority-range
fix(libkernel): report the console's scheduling priority range
2026-10-12 21:38:56 +13:00
Dean 269a3453d1
Merge pull request #4059 from ee6aba54/feat/npwebapi2-add-web-trace-tag
feat(libSceNpWebApi2): export sceNpWebApi2AddWebTraceTag
2026-10-12 21:38:35 +13:00
Dean 57c90b3835
Merge pull request #4056 from Celegans12/fix/libc-terminate-full-what
fix(libc): write the whole what() when terminate reports an exception
2026-10-12 21:38:13 +13:00
milescoviello 89bc9d1082 fix(libc): read %i without the C23 binary prefix in the scanf family on Linux
On Linux sscanf, vsscanf, fscanf and sscanf_s hand their conversions to
glibc. Since glibc 2.38, code built as GNU C++ calls the C23 entry
points (__isoc23_vsscanf, __isoc23_vfscanf, __isoc23_sscanf), whose %i
reads a 0b/0B binary prefix. On main,
sscanf("0b101 x", "%i%n%7s", &value, &end, rest) stores value 5 and
end 5 and leaves "x" for the %s; " -0B11" gives -3. TechnicalDebt
records this.

FreeBSD's %i knows only the 0 and 0x prefixes. FreeBSD 11.4
lib/libc/stdio/vfscanf.c, parseint, lines 345-353 and 371-380:

	case '0':
		if (base == 0) {
			base = 8;
			flags |= PFXOK;
		}
	...
	/* letters ok iff hex */
	case 'A': case 'B': case 'C':
	case 'D': case 'E': case 'F':
	case 'a': case 'b': case 'c':
	case 'd': case 'e': case 'f':
		/* no need to fix base here */
		if (base <= 10)
			break;	/* not legal here */

so "0b101" stores 0, consumes the "0" and leaves "b101", as C17 does
and as the strtol family here already does.

With glibc the scanf family now calls __isoc99_vsscanf and
__isoc99_vfscanf, the entry points GNU C++ used before glibc 2.38
(exported since 2.7), which read %i without the binary prefix. Other
hosts keep std::vsscanf and std::vfscanf. The TechnicalDebt entry is
removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 08:38:06 +00:00
Dean 32e62f2f70
Merge pull request #4039 from ee6aba54/fix/ngs2-sampler-empty-state
fix(libSceNgs2): report EMPTY for a streaming sampler that played its queue
2026-10-12 21:37:52 +13:00
Dean 00fe732b2f
Merge pull request #4032 from fma-rc/feat/pad-input-file-sticks
feat(pad): hold the sticks from the controller command file
2026-10-12 21:37:30 +13:00
Dean 0511e86de9
Merge pull request #3984 from zmeizy/claude/scanf-wide-linux
fix(libc): throw for 16-bit wide scanf conversions on Linux
2026-10-12 21:37:08 +13:00
Dean 286d133a03
Merge pull request #3981 from Kikoarl/feat/sysmodule-audiopropagation-module-id
feat(libSceSysmodule): register libSceAudioPropagation module ID (0x120)
2026-10-12 21:36:45 +13:00
Dean 773f8de7b9
Merge pull request #3824 from xXPBSXx/fix/ces-cp1251-profile
feat(libSceCesCs): add sceCesRefersUcsProfileCp1251 and sceCesMbcsUcsContextInit
2026-10-12 21:36:23 +13:00
Dean 732fc01aaf
Merge pull request #3814 from xXPBSXx/fix/export-ppsa30601-imports
fix(exports): export the calls PPSA30601 imports
2026-10-12 21:36:02 +13:00
Dean Galvin d635d18967 test(agc): check that a Linux page query is answered from the page table
Revoke a checked arena page with mprotect behind the registry and check
that the stored answer comes back, so the test fails without the cache.
Pass the gpu argument that GuestAllocations::Mutation::Add and Protect
now take.
2026-10-12 21:35:24 +13:00
Dean 7b03a42185
Merge pull request #3659 from MarcZX100/carry/win-getdents-name-limit-3327
fix(libkernel): reject oversized Windows directory entry names
2026-10-12 21:35:24 +13:00
Ahir 49e9298706 fix(agc): store only the requested pages of a Linux page query
describePages stored the whole VMA that PROCMAP_QUERY or /proc/self/maps returned. Linux merges adjacent
anonymous mappings with equal flags, so an arena VMA can span GiBs, and the first table miss inside it after
an invalidation rewrote every page of it. Only the pages of the request, rounded out to whole pages, are
stored now, as #1791 describes.

When the guest arena is available, RunUnmappedGapTests checks that a check stores no pages outside its
range, and that protecting and unmapping through the registry clears the stored pages. The registry checks
follow the test on the perf/linux-page-cache branch linked from #1791.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:35:24 +13:00
Swastik-51 9f06176334 fix(agc): cache Linux describePages results 2026-10-12 21:35:13 +13:00
Dean 8f71e3010a
Merge pull request #4259 from Feuris/fix/libc-realloc-null-zero
fix(libc): allocate from realloc(NULL, 0) as malloc(0) does
2026-10-12 21:35:03 +13:00
Adrià 2979ae37a3
Merge pull request #4152 from adriadam10/feat/phase-b
perf(agc): build shader pipeline libraries when shaders are registered
2026-10-12 10:31:42 +02:00
AlxcBTW e785a902b5 fix(agc): keep a host import dropped mid-hold for every batch that hold opens
refreshImports and importAllocation drop an import whose registered run changed (a title growing a
heap) while the GpuMutex hold that drops it may still hold a HostImport pointer from before: a
build's in-place region (UploadFinish flushes pending images between regions, and a flush may
reconcile the imports), an indirect argument or a vertex import. The holder went to the batch open
at the drop, or was destroyed at once with the recorder idle, and the map node the pointer names
was erased. A Submit or Sync later in the hold put the command using the old buffer or address into
a later batch, so the import could be freed before that batch ran and the GPU read an unmapped
page (VK_ERROR_DEVICE_LOST; VK_EXT_device_fault reports READ_INVALID inside the dropped import).

The dropped import's map node now moves into its holder (std::map::extract), so those pointers stay
valid, and the holder is kept by every batch the same hold opens (Recorder::KeepThroughHold), so
whatever the hold records with them completes first. Drops for pages the guest releases (the lease
waiter) keep the old lifetime, and the waiter lets go of what an ended hold kept so it does not pin
the ranges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:30:13 +02:00
AlxcBTW ff349a9a50 test(agc): a host import dropped mid-hold must outlive the hold's later batches
Two deterministic, GPU-free checks (mock device) of the import lifetime when refreshImports drops
an import whose registered run grew, while the GpuMutex hold that took the import may still record
with it: with the recorder idle (the import was destroyed at once) and with a Submit between the
keeping batch and the batch that records the use (the import was destroyed when the keeping batch
completed, with the later batch still in flight).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:30:13 +02:00
Dean 9bc3623517
Merge pull request #4355 from oneandonlydean/up4/fix-4276-stencil-ref-export
fix(agc): export the stencil reference from pixel shaders with VK_EXT_shader_stencil_export
2026-10-12 21:22:09 +13:00
Dean 18028b4920
Merge pull request #4320 from oneandonlydean/up4/fix-frame-dump-queue
fix(agc-driver): queue frame dumps at the dump scale
2026-10-12 21:21:48 +13:00
Dean 3f80d529da
Merge pull request #4309 from oneandonlydean/up4/fix-2776-msaa-enable-single-sample
fix(agc): accept MSAA_ENABLE on a single-sample target sampled at the pixel center
2026-10-12 21:21:26 +13:00
Santhosh Kumar 6b38cdda8c fix(libkernel): report the target size of symbolic links on Windows
_wstat64, the FindFirstFileExW listing and std::filesystem::file_size
report the size of a file symbolic link itself (0). stat therefore gave
0 for linked files, and APR resolved them as empty, so Unity treated a
linked globalgamemanagers as empty and never read it.

stat takes the size from the handle it already opens, which follows the
link. The APR listing skips reparse points, and names missing from it
are sized through stat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:48:56 +05:30
Dean Galvin d37463e76f fix(shader): prove masked lanes unread for every select in one backward pass
MaskedSelectEliminator walked forward from each select to see whether the
lanes its mask excludes are read. Since fda4aa90 the walks pass explicit-LOD
gathers, size queries and guarded image writes, so in a large pixel shader
most of them cover the rest of the program, and the cost grows with the
square of its size (#3504).

The pass now computes, for every value, the set of masks under which it is
unread, from its uses backwards: a use guarded by a condition contributes the
masks that condition implies, a lane-local use adds what its result is unread
under, and any other use contributes nothing. A select is dropped when its
mask is in its own set. Loops are solved as strongly connected components.
The rules for guards, lane-local uses, loops, whole quad masks, selected
execs, rebuilt mask words and guarded first-lane reads are the ones the walk
applied. A first-lane read passes the masks its read mask implies when its
own result is unread outside that read mask, which is solved once per read in
the same way. The walk's step limit, its 64-level implication depth and its
first-lane nesting depth are gone, so a proof no longer depends on the order
of the questions.
2026-10-12 21:16:29 +13:00
milescoviello 19bfa3db29 fix(libkernel): report MSG_TRUNC for SOCK_SEQPACKET records in recvmsg
recvmsg() reads one byte more than the guest buffers hold to see
whether a record did not fit, but only for SOCK_DGRAM sockets. On a
SOCK_SEQPACKET socketpair a record longer than the buffers was cut
short with msg_flags 0: a 6-byte record received into 2 bytes returned
2 and no MSG_TRUNC, and the rest of the record was gone.

FreeBSD's SOCK_SEQPACKET protocol is atomic, sys/kern/uipc_usrreq.c:

	.pr_type =		SOCK_SEQPACKET,
	...
	.pr_flags =		PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED|PR_WANTRCVD|
				    PR_RIGHTS,

and its receive routine, soreceive_generic() in sys/kern/uipc_socket.c,
flags the truncation of an atomic record and drops its rest:

	if (m != NULL && pr->pr_flags & PR_ATOMIC) {
		flags |= MSG_TRUNC;
		if ((flags & MSG_PEEK) == 0)
			(void) sbdroprecord_locked(&so->so_rcv);
	}

which kern_recvit() hands back in msg_flags. recvmsg() now probes for a
longer record on SOCK_SEQPACKET sockets as it does for SOCK_DGRAM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 08:03:38 +00:00
krishalivaibhav a55472cf9f build(agc): avoid copied-write test registration overlap 2026-10-12 13:31:41 +05:30
milescoviello 1337bd7e45 fix(libc): leave a stream that is reading untouched in fflush on Linux
fflush() passed every stream to glibc's fflush(). For a stream that is
reading, glibc seeks the descriptor back and drops the read buffer, and
with a pushed-back character it gets the position wrong: after fgetc()
returned 'a' from "abcdef\n" and ungetc('Z'), fflush() returned 0 and
the next fread() returned "bcdef\n\n". The pushed-back 'Z' was lost and
the last byte came back twice.

FreeBSD's fflush() writes out only a stream that is writing and leaves
every other stream as it is, lib/libc/stdio/fflush.c:

	if ((fp->_flags & (__SWR | __SRW)) == 0)
		retval = 0;
	else
		retval = __sflush(fp);

and __sflush():

	t = fp->_flags;
	if ((t & __SWR) == 0)
		return (0);

fflush() on Linux now returns 0 without calling the host for a stream
whose last operation was not a write (__fwriting() is 0). fflush(NULL)
and streams that are writing are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 08:00:21 +00:00
Adrià Franch b1ee794a66 test(agc): give the formatted buffer vertex case clip distances and the zero-position pixel shader its push slot
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:59:23 +02:00
milescoviello e9c5ae26be fix(libSceNet): read setsockopt timeouts as struct timeval
libkernel's setsockopt() hands options for a libSceNet socket to
sceNetSetsockopt(), whose SO_RCVTIMEO and SO_SNDTIMEO take an int of
microseconds. The POSIX call takes a struct timeval, so main read the
low half of tv_sec as microseconds: {1, 250000} set a 1 microsecond
receive timeout, {0, 500000} set 0, which disables the timeout, and an
out-of-range tv_usec was accepted.

FreeBSD reads a struct timeval, sys/kern/uipc_socket.c, sosetopt():

	case SO_SNDTIMEO:
	case SO_RCVTIMEO:
	...
		error = sooptcopyin(sopt, &tv, sizeof tv,
		    sizeof tv);
	if (error)
		goto bad;
	if (tv.tv_sec < 0 || tv.tv_usec < 0 ||
	    tv.tv_usec >= 1000000) {
		error = EDOM;
		goto bad;
	}

and sooptcopyin() fails a shorter value with EINVAL:

	if ((valsize = sopt->sopt_valsize) < minlen)
		return EINVAL;

setsockopt() on a libSceNet socket now converts the timeval for these
two options, with EINVAL for a short value and EDOM for a negative or
out-of-range one. sceNetSetsockopt() keeps taking microseconds; both
paths share the code that sets the host timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 07:58:06 +00:00
Dean 8c4a295ffb
Merge pull request #4083 from jweidenh/codex/fix-guest-array-callback-abi
fix(libc): preserve the guest ABI for array callbacks
2026-10-12 20:53:57 +13:00
Dean 4e6ef9077a
Merge pull request #3648 from hamb3r/fix/unity-libc-stubs
fix(libc): add missing Unity engine static imports
2026-10-12 20:53:14 +13:00
Adrià Franch f9b592806c perf(recompiler): keep the buffer base misalignment specialized in registration form
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 56d5a4985d perf(recompiler): read the formatted buffer helper's V# words as specialization constants when the format is known
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 60151b66b7 perf(recompiler): keep the format word specialized for buffers accessed with the descriptor's format
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 68164aee2a docs: note that compute shaders keep the specialized form
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 672e43ca67 perf(recompiler): keep compute shaders specialized; only prebuilt vertex and pixel shaders take the registration form
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch d809e6d0db fix(agc): close the library prebuild pool only if it was created
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch acc0a0487d docs: describe shader modules and pipeline libraries built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 361c7e2024 perf(agc): keep oversized shaders specialized and prebuild libraries on their own thread
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch a326fa84f7 fix(recompiler): give registration results a flattened SRT placeholder
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 9eb42ca2d2 fix(agc): destroy pipeline library shader modules once the library is built
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 67556722e1 perf(recompiler): read vertex attribute component selectors at run time when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch e9def903fd perf(agc): prebuild each stage's library alone and keep two descriptor sets with pipeline libraries
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 7f64d14772 perf(agc): build the shader pipeline libraries when graphics stages are resolved at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch d7e0f27d6b perf(agc): describe pipeline set layouts from the compiled shaders alone
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch 4d0b5c7898 perf(agc): give the fragment stage its own descriptor set when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:41 +02:00
Adrià Franch baf3437465 perf(recompiler): read depth-compare state and export mappings at run time when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:33 +02:00
Adrià Franch 765ea6a10f perf(recompiler): keep descriptor heaps uncompacted and read image modes at run time when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:32 +02:00
Adrià Franch ddb6680667 perf(recompiler): read buffer V# words in the shader when modules are built at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-12 09:50:32 +02:00
milescoviello 083c98a067 fix(libkernel): leave a once initializer's own cleanup handlers alone when it throws
pthread_once and scePthreadOnce removed their reset handler with a pop
that runs whatever handler is on top of the cleanup stack. An
initializer that pushed a handler of its own and then threw left that
handler on top, so the pop ran it with dangling state. Both now record
the stack top before pushing the reset handler; on a throw they restore
the stack to it and reset the control directly, and a normal return
restores it as well.

Reported in review by Hussein Kadhim, who fixed it the same way.

Co-authored-by: Hussein Kadhim <husseinkad.dev@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 07:49:09 +00:00
Tyler Westerberg a3cba2d1ff fix(agc-driver): move indices far past every vertex fetch's records to the first zero vertex
Goat Simulator 3 draws a triangle list whose indices are all 0xffffffff
with primitive restart off. Each fetch past a descriptor's records reads
zeros (out-of-bounds select 0 or 1), but the zero-padded vertex copies
were sized to the highest index: 160 GiB, which vkAllocateMemory refused.
When the highest index is at least 64Ki vertices past the largest
per-vertex record count, the draw now uses a copy of its indices with
every index past that count moved to it. Each attribute reads zeros
there as at the original index; only the vertex index the shader sees
changes, so indices closer to the records are left as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:42:49 -04:00
m.peau e19e9145dd fix(libc): truncate strxfrm like FreeBSD's C locale
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:42:28 +02:00
krishalivaibhav dd4504ee43 test(agc): follow repository comment conventions 2026-10-12 13:11:36 +05:30
SandstromPL 872c3ba6ff fix(conventions): check the whole repository when run from a subdirectory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:10:44 +05:30
krishalivaibhav 512ea3ec07 fix(agc): synchronize recorded fast clears with attachments 2026-10-12 13:10:17 +05:30
Rujul Talekar e991645c46 fix(tools): simulate cp1252 default encoding on Python 3.10 in pr_overlap tests
command_output patched subprocess._text_encoding, which does not exist on Python 3.10, so all eight tests errored before their assertions. Use subprocess._text_encoding where available and map io.TextIOWrapper locale to cp1252 on older interpreters, so a subprocess with no explicit encoding decodes as cp1252 on both. Add a behavioral check that default decodes as cp1252 while explicit utf-8 stays correct.

Authored by Rujul Talekar, with Muse Spark 1.3 assistance.
2026-10-12 13:02:14 +05:30
Paritosh Lahre 436e310ddb
fix(conventions): report 3rdparty submodules without a .gitmodules entry (#4304)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:31:24 +13:00
Bharat Yadav f961c52ad8
fix(release): exclude removed libraries from packages (#4297) 2026-10-12 20:31:13 +13:00
Paritosh Lahre 0f0291e39b
fix(tools): run pr_overlap on gh older than 2.48 (#4289)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:31:03 +13:00
Lorky 44e9050a58
fix(import-audit): parse export aliases as C++ tokens (#4196)
Co-authored-by: lorkydey <lorky.contact@gmail.com>
2026-10-12 20:30:54 +13:00
Rain 3048da7c04
docs(compatibility): record DOOM homebrew on Windows with AMD RDNA 4 and RDNA 2 (#4312)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:29:53 +13:00
MarcZX10 656c81ac8b
docs: clarify runtime code generation limits for --to-intel (#4257) 2026-10-12 20:29:46 +13:00
Dean 98c07d8e77
Merge pull request #4111 from jdmagic/fix/kernel-close-net-sockets
fix(libkernel): close() and setsockopt() reach libSceNet sockets
2026-10-12 20:28:00 +13:00
Dean 8b06e64176
Merge pull request #3854 from aryan0078/fix/relinker-debug-module
fix(relinker): resolve debug PRX dependencies by module identity
2026-10-12 20:27:31 +13:00
Dean 4b07baa2f2
Merge pull request #4314 from gravelas/feat/libscevoiceqos-set-connection-attribute
feat(libSceVoiceQoS): export sceVoiceQoSSetConnectionAttribute
2026-10-12 20:27:08 +13:00
Dean 5161070e67
Merge pull request #4273 from poonasor/fix/relinker-move-tls-branch-from-short-access
fix(relinker): move a short guest TLS access's follower branch into its stub
2026-10-12 20:26:47 +13:00
Dean aa2f05a285
Merge pull request #4266 from ducloc080202/fix/libkernel-apr-write-commands
fix(libkernel): record AmmModifyMtypeProtect and AmmRemapIntoPrt commands
2026-10-12 20:26:26 +13:00
Dean 5240dd46a5
Merge pull request #4255 from overlordxrz-source/feat/rudp-get-max-segment-size
feat(libSceRudp): implement sceRudpGetMaxSegmentSize
2026-10-12 20:26:05 +13:00
Dean fedcb3c813
Merge pull request #4117 from PrintOrb/fix/windows-positioned-invalid-descriptors
fix(libkernel): return positioned descriptor errors without CRT reports
2026-10-12 20:25:44 +13:00
Dean 2c51fdfba9
Merge pull request #4112 from jdmagic/fix/net-errors-set-kernel-errno
fix(libSceNet): failures also set libkernel's errno
2026-10-12 20:25:23 +13:00
Dean 4303f39b92
Merge pull request #4110 from jdmagic/fix/net-epoll-control-ops
fix(libSceNet): sceNetEpollControl takes 2 as MOD and 3 as DEL
2026-10-12 20:25:02 +13:00
Dean 84377033a5
Merge pull request #3831 from eljackjoestar-cmd/codex/opus-surround
feat(ajm): decode Opus surround mapping family
2026-10-12 20:24:32 +13:00
Dean 46f5b72e8e
Merge pull request #3623 from milescoviello/fix/pthread-key-numbering
fix(libkernel): number pthread keys from 1 as FreeBSD libthr does
2026-10-12 20:24:15 +13:00
SandstromPL 70f03dc5e5 fix(relinker): write registries after the executable
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 12:48:01 +05:30
Jan Šlégl 7f5cd4480d fix(recompiler): give an early-return selection a merge when its parent's other arm reaches the same join
A selection outside loops whose one arm only returns and whose other arm
branches to a join it does not dominate gets an empty block on that edge
as its merge (splitOneReturnJoin), but only when every other predecessor
of the join dominates the selection or is dominated by it. When the
parent selection's other arm is a region that ends in the same join, the
selection has no structured merge and the shader fails to recompile.

When every structurization attempt fails, Structurize now runs them again
and accepts that split for any join the selection does not dominate. The
split only inserts an empty block on the edge from the selection to the
join. Graphs that structurize on main keep their result.

A synthetic CFG and a synthetic program cover the shape; both fail on main
with "conditional block N has no structured merge".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-12 09:11:25 +02:00
Dean 2ca6198e9a
Merge pull request #3606 from Lorkydey/feat/libkernel-getlogin-r
feat(libkernel): implement getlogin_r using the host account name
2026-10-12 20:01:56 +13:00
ArjenS-LA 100896c1dc fix(relinker): convert guest modules with GNU hash tables 2026-10-12 00:01:49 -07:00
Dean 9231a08b00
Merge pull request #3737 from MarcZX100/codex/json2-init-parameter2-3348
feat(libSceJson2): implement InitParameter2 constructors
2026-10-12 20:01:34 +13:00
ArjenS-LA 4b6bb2f059 fix(relinker): preserve inputs when writing Windows diagnostics 2026-10-12 00:01:25 -07:00
Dean de24bd616d
Merge pull request #4044 from xXPBSXx/fix/export-ppsa07411-vr2-imports
fix(exports): export the PS VR2 calls PPSA07411 imports that no library has
2026-10-12 20:01:13 +13:00
ArjenS-LA e2c24cf038 fix(relinker): accept trailing separators on the Windows origin path 2026-10-12 00:01:09 -07:00
ArjenS-LA 341dafb7ca fix(relinker): rebase each origin in guest runpath lists 2026-10-12 00:00:52 -07:00
ArjenS-LA 9504762edb fix(tools): ignore unreachable CTest registration files 2026-10-12 00:00:28 -07:00
Ahir 99b1b32f31 fix(libkernel): read the fcntl argument by command
fcntl and sceKernelFcntl read a third argument as a 64-bit integer for
every command on a non-socket descriptor. F_GETFD and F_GETFL pass no
third argument, and the commands that take one pass an int or a pointer.
They now read nothing, an int or a pointer, by command. An int read as
a 64-bit value kept whatever the caller left in the upper half of the
register, so F_READAHEAD -1 enabled read-ahead instead of disabling it.
2026-10-12 12:17:26 +05:30
screamm 01b7bb3e2f feat(libkernel): support ioctl on non-socket descriptors
ioctl and _ioctl answered EBADF for every descriptor outside the
libSceNet socket table. Decoded call sites: PS5MC (PPSA99420, FIONBIO x3,
FIONREAD x2, TIOCGWINSZ x3), ProsperoTV (PPSA99003, FIONBIO on a pipe
once poll on pipes is in), XPSemu (PPSA97358, 21 sites).

Following FreeBSD 11.4 kern_ioctl (sys/kern/sys_generic.c:758),
vn_ioctl (sys/kern/vfs_vnops.c:1488), pipe_ioctl (sys/kern/sys_pipe.c:1346)
and randomdev_ioctl (sys/dev/random/randomdev.c:301), release/11.4.0
8c639945: FIONBIO sets or clears O_NONBLOCK through the same status
flags as fcntl F_SETFL (EFAULT for a null argument before EBADF);
FIONREAD reports the size past the offset of a file, the queued bytes of
a pipe's read end, 0 on its write end, ENOTTY on the random device, and
throws on a directory or another character device; termios requests
(group 't', TIOCGWINSZ included) fail with ENOTTY, as tcgetattr already
takes these descriptors as not a terminal; any other request throws
naming the request and descriptor kind. Sockets keep their path
unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 12:17:26 +05:30
screamm 591e8ddadc feat(libkernel): support fcntl on non-socket descriptors
fcntl and sceKernelFcntl answered EBADF (sceKernelFcntl threw) for
every descriptor outside the libSceNet socket table, so files, pipes,
directories and descriptors 0 to 2 could not be queried or changed.

Observed: Yamagi Quake II (PPSA99007) stops with
"Sys_Error: change stdin to blocking Bad file descriptor", from
fcntl(fileno(stdin), F_SETFL, fcntl(0, F_GETFL, 0) & ~FNDELAY)
(yquake2 src/backends/unix/system.c:81-86).

Predicted from the titles' sources and decoded call sites: XPSemu
(PPSA97358, 97 fcntl sites: F_GETFD 12, F_SETFD 20, F_GETFL 8,
F_SETFL 9, F_DUPFD 1, F_DUPFD_CLOEXEC 7, F_GETLK 9) fails in
qemu_init_main_loop, where its pipe2 (pipe plus F_SETFD FD_CLOEXEC) and
glib's g_unix_set_fd_nonblocking (F_GETFL, F_SETFL) build the event
notifier (util/event_notifier-posix.c:44-67); VLC (PPSA85300, 43 sites,
F_RDAHEAD on every file it opens), RetroArch (PPSA99169, 17),
Porpoise (PPSA99764, 13) and Ruffle (9) call it on files and pipes.

The commands follow FreeBSD 11.4 kern_fcntl and kern_dup
(sys/kern/kern_descrip.c:479-799, 812, release/11.4.0 8c639945):
F_GETFD/F_SETFD keep the close-on-exec flag per descriptor, F_GETFL
reports the host access mode with the status flags, F_SETFL changes
only O_NONBLOCK, O_APPEND, O_ASYNC, O_FSYNC, O_DIRECT and FRDAHEAD,
F_DUPFD/F_DUPFD_CLOEXEC give the lowest free descriptor at or above the
start through dup (EINVAL for a negative start), F_DUP2FD goes through
dup2, F_RDAHEAD/F_READAHEAD set FRDAHEAD on files (EBADF on pipes,
ENOTTY elsewhere), and unknown commands fail with EINVAL. Status flags
live in a guest table shared by dup, dup2 and F_DUPFD like an open file
description. O_NONBLOCK switches a pipe (PIPE_NOWAIT on Windows, where an
empty read and a full write now report EAGAIN; the host flag on Linux).
Record locks use the host POSIX locks on Linux and throw on Windows.
Changes the host cannot model throw naming the flag and descriptor kind.
Sockets keep their path unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 12:17:25 +05:30
Dean Galvin 22d662eda7 fix(agc): export the stencil reference from pixel shaders with VK_EXT_shader_stencil_export 2026-10-12 19:44:41 +13:00
pushkarreddyy 2781077ace feat(libkernel): answer getrlimit for FreeBSD resources 2026-10-12 12:09:41 +05:30
Dean d06c065657
Merge pull request #3895 from CouchRiv/fix-shader-vcmpx-f32-family
fix(shader): keep f32 denormals in compares when denormals are kept
2026-10-12 19:39:34 +13:00
Dean 7f7f961bf8
Merge pull request #3739 from eljackjoestar-cmd/codex/masked-first-lane-proof
fix(shader): prove masked writes through guarded first-lane reads
2026-10-12 19:39:13 +13:00
pushkarreddyy d8b42473d7 feat(libkernel): support MIB 1.37 (kern.arandom) in sysctl 2026-10-12 12:07:45 +05:30
fma-rc 21b9e2efeb
feat(agc): select the swapchain present mode with ANYPS5_PRESENT_MODE 2026-10-12 08:30:00 +02:00
Felipe Arce 4dfe0526b8 fix(agc): link the texture mip layout into the BDA device tests 2026-10-12 03:26:02 -03:00
Celegans12 67ddb3624e fix(relinker): preserve load failures of present optional providers
Probe an optional provider before loading it and skip only direct file or
path absence. A present DLL with a missing dependency must report the
original loader failure instead of being treated as an absent provider.

Check the generated PE on every host: each optional provider's path
reference must reach a GetFileAttributesW call through its IAT slot whose
success branch continues to the LoadLibraryExW call.

Extend the native-provider regression with a generated DLL that imports
a missing dependency, while retaining the successful absent-file case.
2026-10-12 08:19:49 +02:00
Felipe Arce 6c94d31d77 test(agc): render into packed mip tails through the guest-memory fallback 2026-10-12 03:17:32 -03:00
Felipe Arce 9394c74301 fix(agc): keep untailed color targets on their own detiler layout 2026-10-12 03:17:32 -03:00
Avijit Singh 485c0f3346 style(agc): keep mip layout API comment-free
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 03:17:32 -03:00
Avijit Singh 89c128782c fix(agc): render nonresident packed mip targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 03:17:32 -03:00
Avijit Singh c58c9488e5 test(agc): cover packed color mip detiling
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 03:17:32 -03:00
Avijit Singh c914bcd721 feat(agc): describe color mip targets with parent layout
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 03:17:32 -03:00
Claude fd0d55ce21
fix(tools): follow Depends on chains in pr_overlap
pr_overlap only skipped a pair when one pull request named the other
directly. In a stack where #3 depends on #2 and #2 on #1, #1 and #3 were
reported as overlapping, and two pull requests built on the same #1 were
reported for the files and exports both inherit from it. Dependencies are
now followed through open pull requests, and what a shared dependency adds
is left out of the same-file and same-export columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0189deyapHNNqKQJboZBJQei
2026-10-12 06:10:56 +00:00
Dean Galvin fdfbeba8ad fix(agc): accept MSAA_ENABLE on a single-sample target sampled at the pixel center 2026-10-12 19:07:15 +13:00
Dean 2ccbd376f8
Merge pull request #2169 from authurtabo-byte/feat/agc-uniform-sample-locations
feat(agc): support uniform custom MSAA sample locations
2026-10-12 19:06:44 +13:00
abhinav29102005 99a39859db test(libkernel): assert memory type propagation from batch commit entry 2026-10-12 11:34:03 +05:30
abhinav29102005 4f947dab16 test(libkernel): dispatch memory pool batch op 1 commit entry in test 2026-10-12 11:33:47 +05:30
abhinav29102005 ed3ca36b54 test(libkernel): construct batch commit entry for memory pool test 2026-10-12 11:33:19 +05:30
abhinav29102005 e106b3ba9b test(libkernel): assert neighbor page isolation after pool commit 2026-10-12 11:32:55 +05:30
abhinav29102005 f608965b47 test(libkernel): assert direct memory type update after pool commit 2026-10-12 11:32:37 +05:30
abhinav29102005 e04347ca60 test(libkernel): call sceKernelMemoryPoolCommit in direct memory test 2026-10-12 11:32:24 +05:30
abhinav29102005 899e7ddd0a test(libkernel): declare sceKernelMemoryPoolCommit in guest memory test harness 2026-10-12 11:32:07 +05:30
abhinav29102005 aeb131a5b7 fix(libkernel): forward entry type in sceKernelMemoryPoolBatch op 1 2026-10-12 11:31:52 +05:30
abhinav29102005 7b552bf143 fix(libkernel): forward type parameter from sceKernelMemoryPoolCommit 2026-10-12 11:31:39 +05:30
abhinav29102005 337db209fa fix(libkernel): route memory type to DoMtypeprotect in PoolCommit 2026-10-12 11:31:25 +05:30
abhinav29102005 21b0eb7fae refactor(libkernel): accept memory type in PoolCommit helper signature 2026-10-12 11:31:08 +05:30
JAB-dev deaa2e3ef6 test(agc): draw into a 1_5_5_5 target and read the 16 bits back
Draws 32_ABGR exports into a tiled and a linear format 17 target and compares every texel with
the layout X in bits 0-4, Y in 5-9, Z in 10-14, W in bit 15, including the X/Z-swapped pairs, rounding
edges and texels outside the scissor. Reverting the X/Z exchange fails it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 07:59:29 +02:00
Dean Galvin abc1cfa57d fix(agc-driver): queue frame dumps at the dump scale
A frame presented from guest memory with APS5_DUMP_FRAMES is read back
at the size of the display buffer, and that whole copy went into the
dump writer's queue with the scale beside it (31.6 MiB for a 3840x2160
buffer). The queue holds 64 MiB, so the third frame the writer had not
finished ended the run with "frame dump queue exceeded 64 MiB". A frame
blitted from the resident image is already reduced on the GPU and queued
at the reduced size.

The readback is now reduced by the dump scale when the slot retires and
queued at that size, the same pixels the writer kept before. With
APS5_DUMP_SCALE=1 nothing is reduced and the limit is reached as before.

video_out_frame_dump_queue presents four 3840x2160 frames from guest
memory while the writer is held on the first file and compares every
dump with the decoded display buffer.
2026-10-12 18:54:34 +13:00
winstrex 749541f653 feat(libkernel): implement sceKernelEnableDmemAliasing
Direct memory can already be mapped more than once, so there is no
aliasing to enable and the call returns 0. ProsperoEden (PPSA99008)
imports it and calls it before mapping the same direct memory again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:40:10 -03:00
Leonardo 216984afc6
feat(libkernel): implement sceKernelGetCpuTemperature 2026-10-12 07:37:44 +02:00
mir 89b4b2475e
Merge branch 'main' into aureau/carry-libc-strtod-no-conversion-zero 2026-10-12 01:34:06 -04:00
Dean Galvin 5b7cb8d126 perf(libkernel): find direct mappings that share physical memory through an index 2026-10-12 18:29:46 +13:00
Utku Halis 661f8e1e7c feat(libSceAgc): implement sceAgcAcbWaitUntilSafeForRendering 2026-10-12 08:26:47 +03:00
AlxcBTW b42ef24e07
fix(libs): keep thread_local objects with destructors out of module teardown on Windows (#4029)
* fix(agc): keep the driver's per-thread scratch out of thread_local teardown

With MinGW's emulated TLS, a thread_local with a destructor in a DLL is
destroyed after its storage is gone: when a std::thread ends, winpthread
runs libgcc's emutls key destructor, which frees the thread's thread_local
storage, and only then does the loader's DLL_THREAD_DETACH run the DLL's
tls_atexit list, so the destructors run on freed memory. The queue worker
touches four of them in libSceAgcDriver (the dispatch-ahead map, the
pending waits, the draw-snapshot compare vectors and the image decode
memo), and Driver::stop's join of the worker then corrupts the heap.
Under cdb's checking heap agc_driver_draw_cache_reuse stopped at the
worker's exit with heap corruption in all 127 runs, with graphics
pipeline libraries, with APS5_NO_PIPELINE_LTO=1 and with APS5_NO_GPL=1.
Without it the damage shows intermittently, as exit 0xc0000374 (2 of 143
runs with a cold NVIDIA shader cache) or as a fault in whatever allocates
next, such as NVIDIA's compiler on the optimized-link thread (#2980).

These objects now live in HostThreadLocal, fiber-local storage that owns
them, as the recorder's buffers do since e424b6b7b.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(libs): keep thread_local objects with destructors out of module teardown

The teardown order behind the driver's heap corruption holds in every
module: with MinGW's emulated TLS a thread's thread_local storage is freed
before the module's DLL_THREAD_DETACH runs its thread_local destructors,
so they run on freed objects. PreciseSleepUs's timer (used, among others,
by the video-out vblank thread) then closes a stale handle; libkernel's
directory path, socket waker and UUID random device, libSceRandom's random
device and libScePosixForWebKit's random device and host lookup free or
close stale objects. They move to HostThreadLocal. The other thread_locals
in the modules are trivially destructible or only built for Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(libs): fail when a module registers a thread_local destructor

prx_thread_local_destructors lists the symbols of every built module and,
where MinGW's thread_local destructor support is linked in, disassembles
the module for calls to __cxa_thread_atexit outside libc's registration of
guest destructors. A module that keeps a thread_local with a destructor
fails it with the function that registers one: with main's libSceRandom
it reports sceRandomGetRandomNumber, and with this branch all 122 modules
pass, libc being the only one that links the support.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(agc): keep the image memo behind its pointer

The image decode memo went into HostThreadLocal as the whole array. On
Linux, where HostThreadLocal is a plain thread_local, that put 1024 memo
entries into every thread's TLS block instead of one pointer. It keeps
its unique_ptr as before, now owned by HostThreadLocal, so Linux builds
the same thread_local as main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dean Galvin <dean.galvin@live.com>
2026-10-12 18:25:29 +13:00
Aarav 74defef675 fix(libSceNet): preserve successful stream recvfrom results 2026-10-12 10:54:08 +05:30
Tyler Westerberg 2add25cea0 feat(agc-driver): replay a request as a prepared artifact with --prepare
agc_shader_replay compiles a request through Recompile, the per-draw path.
Shaders the driver prepares at registration go through PrepareShader
instead and produce a different, larger artifact, so a failure or the size
of that artifact could not be reproduced from the dumped request.
--prepare compiles the request with PrepareShader and prints the artifact's
SPIR-V size, or the first line of the failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:21:48 -04:00
Dean 6e653bef51
Merge pull request #3675 from MrMha/fix/oracle-cache-current
fix(hw-oracle): invalidate cached builds when inputs change
2026-10-12 18:21:47 +13:00
Tyler Westerberg bad49ba2c4 feat(libSceVoiceQoS): export sceVoiceQoSSetConnectionAttribute
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:21:46 -04:00
Dean f9984863e6
Merge pull request #3600 from CouchRiv/fix-libc-fmod-errno
fix(libc): fmod leaves errno unchanged
2026-10-12 18:20:20 +13:00
Dean 5d7be6bdc8
Merge pull request #4003 from zmeizy/claude/memory-pool-batch-type-protect
fix(libkernel): apply the memory type in sceKernelMemoryPoolBatch typ…
2026-10-12 18:20:05 +13:00
Dean 0ed0d3c9b6
Merge pull request #4033 from MarcZX100/codex/carry-shader-wqm-live-quad-bit-2548
fix(shader): fold current s_wqm pixel lane
2026-10-12 18:19:43 +13:00
Dean abd73fbc0d
Merge pull request #4002 from zmeizy/claude/barrier-destroy-after-release
fix(libkernel): let pthread_barrier_destroy wait for released waiters
2026-10-12 18:19:21 +13:00
Dean 6d9a680fbb
Merge pull request #3878 from fma-rc/fix/agc-zero-position-vertex
fix(shader): clip primitives with an all-zero clip position
2026-10-12 18:18:41 +13:00
Diversao cd067d1569 fix(agc): release parked host imports a pinned guest range waits for
A device replaced at AttachWindow keeps its host imports in
HostImports::parked until it is destroyed, and each parked import keeps
its guest ranges pinned. A guest munmap, mprotect or free of such a range
spun in the pin waiter until APS5_PIN_WAIT_MS and then failed, because the
waiter only looked at the live imports. The replaced device was already
waited idle by PrepareForReplacement, so the waiter now drops the parked
imports over the range.

agc_parked_import_unmap imports a range on one device, again on a second
one, and unmaps it with a 3 s pin wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:00:48 -03:00
Aarav 6197edea2b fix(libkernel): report copied socket address lengths 2026-10-12 10:21:17 +05:30
BharatYadav007 f0e852ae27 fix(libc): normalize valid mktime minus-one results 2026-10-12 10:18:20 +05:30
fma-rc 9db923e907
fix(shader): clip primitives with an all-zero clip position 2026-10-12 06:46:34 +02:00
Dean e013f8c9c5
Merge pull request #3834 from jackthereaper2006/docs/doom-linux-amd
docs: record DOOM homebrew on Linux with an AMD GPU
2026-10-12 17:35:57 +13:00
Dean 66ab8753bf
Merge pull request #3780 from MrMha/fix/unwind-record-bounds
fix(relinker): validate file-backed unwind record ranges
2026-10-12 17:35:37 +13:00
Dean 3eabeaaa81
Merge pull request #3754 from Amoenus/codex/test-app-info-child-result-maina11
test(libkernel): verify app info missing metadata errors
2026-10-12 17:35:16 +13:00
Dean 1a8fd39199
Merge pull request #3715 from Lorkydey/feat/libkernel-wait
feat(libkernel): implement wait through guest waitpid
2026-10-12 17:35:02 +13:00
Dean 7bcadb1e56
Merge pull request #3680 from droid2299/fix/libkernel-rusage-children
fix(libkernel): support RUSAGE_CHILDREN in getrusage
2026-10-12 17:34:48 +13:00
TibixDev 2441a4b0d9 fix(agc): retry failed host imports after range replacement
Retain weak identities and the full failed span so a replacement of either owner or a shorter remaining run retries the import. Keep unchanged failures cached across unrelated mapping changes without pinning their allocations. Existing upstream import lifetime, span windows and Windows fallback remain in place. AI-assisted implementation.
2026-10-12 07:34:15 +03:00
Dean 69138616c3
Merge pull request #3653 from QRMOE/fix-libc-strftime-literal-conversions
fix(libc): preserve strftime literal conversions
2026-10-12 17:34:15 +13:00
Dean a2c4176f7e
Merge pull request #3631 from arreina/pr/json-test-leak
test(json2): destroy the value before constructing over it
2026-10-12 17:34:01 +13:00
Dean 1d1acb1266
Merge pull request #3629 from QRMOE/fix-libc-dirname-result-length
fix(libc): check dirname result length
2026-10-12 17:33:41 +13:00
danzaio 56df893667 fix(agc): preserve dumps for non-standard shader failures
Capture the request once before rethrowing from the shared handler. Standard exceptions keep the shader address, stage, optional dump filename and full message; non-standard exceptions remain unchanged after capture.

AI-assisted: yes.
2026-10-12 01:33:37 -03:00
danzaio e71e3a4b3f fix(agc): name the shader address and stage in preparation failures
PrepareShaderWithDiagnostics dumped the request but rethrew the raw error, so a failure never said which shader it came from. Wrap it with the shader address and stage, keeping the dump. AI-assisted: yes.
2026-10-12 01:33:37 -03:00
danzaio 768929bb76 test(agc): preparation failures name the shader address and stage
FailureCapture now requires the code address and stage in the diagnosed failure, with and without the request dump. Fails before the wrap, passes after. AI-assisted: yes.
2026-10-12 01:33:37 -03:00
Dean bb67fe1a34
Merge pull request #3612 from karim200003/fix/libc-fgets-nonpositive-size
fix(libc): fail fgets with a size of 0 or less like FreeBSD
2026-10-12 17:33:20 +13:00
Dean e929880df4
Merge pull request #4008 from zmeizy/claude/getenv-invalid-name-errno
fix(libc): set EINVAL when getenv gets an invalid name
2026-10-12 17:33:03 +13:00
Dean 3fefe8a32f
Merge pull request #4010 from zmeizy/claude/getenv-stable-pointers
fix(libc): keep getenv results valid when other variables change
2026-10-12 17:32:42 +13:00
Dean 8b33507dc3
Merge pull request #4007 from zmeizy/claude/atexit-with-cxa-atexit
fix(libc): run atexit handlers in one order with __cxa_atexit destruc…
2026-10-12 17:32:21 +13:00
Dean fcb57611e4
Merge pull request #4221 from oneandonlydean/up4/in-place-index-highest-2
perf(agc): keep the highest index of a large in-place index buffer while it is unchanged
2026-10-12 17:32:00 +13:00
Dean 62bd3c9e68
Merge pull request #3841 from Kikoarl/feat/sysmodule-share-module-id
feat(libSceSysmodule): register libSceShare module ID (0x10F)
2026-10-12 17:31:46 +13:00
Dean 2da042eee0
Merge pull request #3933 from fma-rc/fix/system-service-language-param
fix(libSceSystemService): answer parameter 400 with the console language
2026-10-12 17:31:24 +13:00
Dean eb91f4e860
Merge pull request #4049 from Mouhand-Kaddo/fix/demons-readonly-resummarize
fix(agc): handle Demon's Souls read-only depth resummarize
2026-10-12 17:30:54 +13:00
Dean 6d1cee6d3f
Merge pull request #3593 from ahir061/fix/recompiler-prime-shared-mutex
fix(shader): lock recompiler shared mutexes once when created
2026-10-12 17:30:28 +13:00
Dean c22957f7b0
Merge pull request #3951 from Scramblrrrr/codex/constant-phi-definitions-current-main
fix(shader): preserve distinct SSA definitions when folding Phi inputs
2026-10-12 17:30:04 +13:00
Dean 32cb3fea95
Merge pull request #3932 from CouchRiv/fix-shader-f16-denorm-flush-family
fix(shader): flush f16 denormals in unary, frexp and conversion ops per the float mode
2026-10-12 17:29:43 +13:00
Dean 6b0ce1513d
Merge pull request #4018 from Mouhand-Kaddo/fix/demons-loop-continue
fix(shader): keep Demon's Souls loop shader valid after optimization
2026-10-12 17:29:21 +13:00
Dean 991378066e
Merge pull request #3661 from Celegans12/fix/agc-own-resolved-dispatch-state
fix(agc): own resolved dispatch state through thread exit
2026-10-12 17:29:00 +13:00
Dean 35ef0b7377
Merge pull request #3937 from hansjm10/fix/libkernel-munmap-unmapped
fix(libkernel): let munmap succeed over a range with nothing mapped
2026-10-12 17:28:36 +13:00
Dean 5aa0e15a4f
Merge pull request #3867 from tv7/fix/videoout-attribute-change-pending-flip
fix(videoout): accept a buffer attribute change while a flip is pending
2026-10-12 17:28:15 +13:00
Dean 18af217211
Merge pull request #3645 from alfalfa-star/fix/recompiler-mesh-grid-size-sgpr
fix(recompiler): read NumWorkgroups in every mesh shader so RADV sizes its user data
2026-10-12 17:27:54 +13:00
Ondra97 1e429dc23f test(libs): cover watched recvfrom sender outputs 2026-10-12 06:10:09 +02:00
eljackjoestar-cmd 9873fae1ef perf(libkernel): commit Windows direct backing when mapped 2026-10-12 07:59:34 +04:00
poonasor c6f934a3d0 fix(relinker): move a short guest TLS access's follower branch into its stub
A short fs-prefixed TLS access is patched with a 5-byte jump by
relocating the following instructions into the stub, but any branch
there was rejected outright. NHL 27 hits this on every stack-protector
epilogue: fs:xor rax,[rbx] immediately followed by jne __stack_chk_fail.

Allow relative conditional branches and short jumps: re-encode rel8
forms as their rel32 equivalents, rebase the displacement when the
stub is emitted, and keep rejecting loop/jrcxz, calls, returns, and
segment-prefixed followers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:44:54 -04:00
authurtabo-byte 605741d39f fix(agc): key GPL libraries by sample-location enablement 2026-10-11 20:43:05 -07:00
codingreapermaps c6be0e95cc fix(libkernel_sys): read relative symbolic links on Windows
readlink threw for every Windows reparse point, including the links
symlink creates. Read the target of a relative symbolic link from its
reparse data and return it with forward slashes. Absolute targets,
junctions and other reparse points still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:39:39 +01:00
Ondra97 8f33897275 fix(libs): allow socket receives into watched guest memory 2026-10-12 05:37:35 +02:00
authurtabo-byte fb7615e307 fix(agc): key GPL libraries by custom sample locations 2026-10-11 20:36:04 -07:00
Michon 33efe5ac5d fix(agc): the standard 8x pattern's last sample is at (7, -7)
Vulkan's standard 8x sample 7 is (0.9375, 0.0625), (7, -7) in signed sixteenths; the table had (7, -8), so the
standard pattern (PPSA99902's PA_SC_AA_SAMPLE_LOCS words 0xbd153fd1 / 0x9773f95b) was refused as nonstandard.
Regression row with those words.

Reported by @Amoenus.

Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9a1a0672cac0f8e3dcaa6e28cbe6b7b684a40a1f)
2026-10-11 20:36:04 -07:00
authurtabo-byte 9bc72d105e fix(agc): preserve graphics behavior after rebase
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-11 20:36:04 -07:00
authurtabo-byte e28dcc0c12 fix(agc): validate custom sample location depth formats 2026-10-11 20:36:04 -07:00
authurtabo-byte c9e48e5ae2 feat(agc): support uniform custom MSAA sample locations 2026-10-11 20:36:04 -07:00
ducloc080202 2cf929db08 fix(libkernel): record AmmModifyMtypeProtect and AmmRemapIntoPrt commands 2026-10-12 10:33:45 +07:00
Nithishvelan M bc71f97667 fix(libkernel): return after NotImplemented in Windows shm_unlink 2026-10-12 09:03:06 +05:30
Dextroid17 ef3b121e44 fix(libSceAmpr): export sceAmprAmmSetPageTablePoolOccupancyNotificationThreshold
Resolves NID touqMEt6qXQ, the last import Trails in the Sky 2nd Chapter
(PPSA35169) is left missing on libSceAmpr.prx once the libkernel pair in #4214
is recorded. No reference describes the function's contract, so it throws via
the project's NotImplemented_nid_no_patch pattern rather than guessing a result
that a caller would act on.

sceAmprAmmGetUsageStatsData (KqiWXLgCVe0) is deliberately not included: #3814
exports it and #4207 answers it from a cited layout.

See issue #4214.
2026-10-11 23:23:44 -04:00
danzaio b390831a58 docs(user): relocate Windows standard handles logging note to Windows runtime layout section 2026-10-12 00:18:47 -03:00
danzaio ae96779914 test(relinker): verify Windows DLL CRT output handles 2026-10-12 00:15:49 -03:00
ChatGPT (local) 6effc5dcec test(relinker): verify GUI startup log replacement and unavailable log
Cover successful GUI stdout logging, replacement of stale log, and startup when log path is a directory. AI-assisted: ChatGPT.
2026-10-12 00:15:49 -03:00
Doston Abdullayev ab3e926058 feat(relinker): write the output of a Windows executable without standard handles to anyps5.log
A --windows-gui build started from Explorer, or any Windows executable
started without a standard output or error handle, lost everything it
printed: the entry stub's messages, the libraries' stdout and stderr,
uncaught exception messages and crash reports.

Before it enters its directory or loads a library, the entry stub now
checks the standard output and error handles, and gives each missing one
anyps5.log beside the executable. The C runtime of the libraries it then
loads adopts the file. Executables started with handles are unchanged,
and one that cannot create the file starts as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 00:15:49 -03:00
Dean d146ec1b66
Merge pull request #3640 from MarcZX100/feat/libc-math-predicate-exports-3624
feat(libc): export isnanf and __signbitl
2026-10-12 16:12:58 +13:00
Dean a18b088d39
Merge pull request #4005 from zmeizy/claude/posix-deadline-overflow
fix(libkernel): clamp POSIX deadlines beyond the clock range instead …
2026-10-12 16:12:38 +13:00
milescoviello 4ece6750b7 fix(libc): print the guest errno message for %m in the printf family
FreeBSD's printf formats %m as the message for the errno value at the
time of the call. On Linux a format with %m went to glibc, which looks
the number up in Linux's table, so guest errno values above 34 got
another error's text: with errno 35 (EAGAIN) "[%m]" printed
"[Resource deadlock avoided]" instead of "[Resource temporarily
unavailable]", and errno 63 (ENAMETOOLONG) printed "Out of streams
resources". On Windows, and on Linux when the format also had a wide
argument, the guest formatter threw on %m.

FreeBSD 11.4, lib/libc/stdio/vfprintf.c:

	saved_errno = errno;
	...
		case 'm':
			cp = strerror(saved_errno);
			size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
			sign = '\0';
			break;

The guest formatter now saves errno when it starts and formats %m as a
string with the guest strerror_r text, so width, precision and the -
flag apply as FreeBSD's string path applies them. On Linux a format with
%m goes to the guest formatter like one with a wide argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:12:27 +00:00
Dean 5a59d4e257
Merge pull request #3979 from zmeizy/claude/sema-remaining-timeout
fix(libkernel): report the remaining time from sceKernelWaitSema
2026-10-12 16:12:08 +13:00
Dean d2d4c07aab
Merge pull request #3978 from zmeizy/claude/asprintf-guest-wide
fix(libc): format 16-bit wide arguments in asprintf on Linux
2026-10-12 16:11:47 +13:00
Dean 1470522ff3
Merge pull request #3964 from MarcZX100/codex/carry-nanosleep-rmtp
fix(libkernel): leave remaining time untouched when nanosleep completes
2026-10-12 16:11:26 +13:00
Feuris d119945a45 fix(libc): allocate from realloc(NULL, 0) as malloc(0) does
realloc(NULL, 0) returned NULL without allocating anything, while malloc(0) returns a unique pointer. C11 7.22.3.5p3 says realloc with a null pointer behaves like malloc for the specified size, so code that grows an empty buffer from zero elements (p = realloc(p, n * size) with n == 0) and treats NULL as out of memory failed on its first call.

FreeBSD 11.4 never returns NULL from realloc for a zero size; je_realloc rounds the size up before choosing between resizing and allocating (contrib/jemalloc/src/jemalloc.c, je_realloc).

A null pointer with size 0 now reaches the allocator's realloc, which allocates as malloc(0) does. A non-null pointer with size 0 is still freed and NULL returned, as before.

Co-authored-by: milescoviello <kitslayer29@gmail.com>
2026-10-12 00:11:17 -03:00
Dean 9eb1486e39
Merge pull request #3957 from MarcZX100/codex/carry-recvfrom-stream
fix(libkernel): report no sender for stream recvfrom calls
2026-10-12 16:11:05 +13:00
Dean eb189f65d6
Merge pull request #3944 from hugodearaujo/fix/operation-mode-console
fix(libkernel): report the operation mode the console reports
2026-10-12 16:10:44 +13:00
Dean 5fe4bebec6
Merge pull request #3923 from AchrafReyani/fix/libkernel-close-ebadf
fix(libkernel): close an unopened descriptor on Windows without the invalid-parameter report
2026-10-12 16:10:27 +13:00
Dean e088868801
Merge pull request #3908 from GalaxyGamingFR/fix/conventions-wrapped-declarations
fix(conventions): treat wrapped declarations as declarations
2026-10-12 16:10:06 +13:00
Dean 796daf5ef0
Merge pull request #3906 from GalaxyGamingFR/fix/progress-render-sliver
fix(progress): skip cells for rectangles without area
2026-10-12 16:09:45 +13:00
AlxcBTW a7ed14c74b Merge branch 'main' into fix/recompiler-flat-p10-provoking-v2-2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 05:09:22 +02:00
Dean c12cb634f1
Merge pull request #4249 from oneandonlydean/up4/fix-skip-messages
test(agc): word the tessellation and oversized dispatch skips as device limitations, as check_skips expects
2026-10-12 16:09:15 +13:00
Dean 4dfa8506b3
Merge pull request #1680 from emirplus/fix/savedata-memory-metadata
fix(savedata): recover from metadata setup failure
2026-10-12 16:08:53 +13:00
Dean 01e5f3b8a8
Merge pull request #3977 from hansjm10/fix/libscenet-sockaddr-len
fix(libSceNet): accept guest socket addresses whatever their sa_len
2026-10-12 16:08:32 +13:00
Dean f0674d3c08
Merge pull request #3968 from babyhuey/feat/libkernel_sys-openat
feat(libkernel_sys): implement openat
2026-10-12 16:08:11 +13:00
Dean f3abf38307
Merge pull request #3855 from Lorkydey/fix/libkernel-utc-dst-width
fix(libkernel): limit UTC-to-local DST output to 32 bits
2026-10-12 16:07:49 +13:00
Dean 26d87eec20
Merge pull request #3850 from SandstromPL/fix/relinker-module-dir-root
fix(relinker): accept the input's directory as a module directory
2026-10-12 16:07:27 +13:00
Dean f5ce5957c1
Merge pull request #3797 from YossiYad/carry/audioout-hdmi-monitor-info
feat(libSceAudioOut): implement sceAudioOutSysGetHdmiMonitorInfo
2026-10-12 16:07:06 +13:00
AlxcBTW 48654bdc89 fix(shader): apply VOP3P neg_lo/neg_hi to packed 16-bit integer sources
The packed integer ops (v_pk_add/sub/mul_lo/mad/min/max/shift) read their
16-bit sources without the VOP3P negate bits. Hardware negates a 16-bit
source by flipping bit 15 for integer ops too, and Sony's compiler relies
on it: UE5's TSR history update clamps its -1 neighbour offsets with
v_pk_max_i16 v14, neg(lit 0x7fff), v14, i.e. max(-1, minY - y). Without
the modifier that became max(0x7fff, x), the x-1/y-1 taps of the 3x3
input filter read out of bounds as zero, and the history lost ~16 % of
its energy every frame (Sword of the Sea's missing glow).

The new execution test covers every packed integer op with neg_lo and
neg_hi, op_sel interplay, clamp and the TSR literal case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fa2MbmdFLVr8YHuVjucHE
2026-10-12 04:57:52 +02:00
Gustavo Ariel Gamarra Rojas bff955a3e4 fix(agc): match any format when a storage dump shape names none 2026-10-11 23:55:12 -03:00
milescoviello 42bf2a2ad3 fix(libc): format guest wide arguments in syslog on Linux
vsyslog formats the message with the host's vsnprintf on Linux, so a
%ls, %S, %lc or %C argument is read as glibc's 32-bit wchar_t instead
of the guest's 16-bit units. glibc fails the conversion and the message
is dropped: on main syslog(LOG_DEBUG, "wide %ls %d %S", u"guest", 5,
u"text") writes "[syslog:15] " with nothing after it. Windows already
formats syslog messages with the guest formatter, and the narrow printf
family does so on Linux for formats with a guest wide conversion.

FreeBSD 11.4 lib/libc/gen/syslog.c line 229 formats the message with

	(void)vfprintf(fp, fmt, ap);

and lib/libc/stdio/vfprintf.c (lines 831-843) converts %S and %ls from
the guest's wchar_t:

	case 'S':
		flags |= LONGINT;
		/*FALLTHROUGH*/
	case 's':
		if (flags & LONGINT) {
			wchar_t *wcp;
	...
				convbuf = __wcsconv(wcp, prec);

vsyslog now formats through the guest's vsnprintf, which hands formats
with a guest wide conversion to the guest formatter (UTF-8 output, as
for printf) and every other format to glibc as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:52:07 +00:00
milescoviello 04c5c8da7a fix(libc): accept the ' flag in the wide printf family
The wide formatter behind swprintf, vswprintf, wprintf and snwprintf_s
does not know the ' (thousands grouping) flag: it takes ' for the
conversion and fails, so on main swprintf(buffer, 32, L"%'d", 1234567)
returns -1 with errno EINVAL and an empty buffer. The narrow guest
formatter accepts the flag since #3567.

FreeBSD 11.4 lib/libc/stdio/vfwprintf.c takes it as a flag
(lines 613-615):

	case '\'':
		flags |= GROUPING;
		goto rflag;

and grouping_init (lines 129-147) adds separators only while
*gs->grouping != CHAR_MAX. In the C locale, the only one the guest's
setlocale accepts, lib/libc/locale/lnumeric.c (lines 44-50) has

	static char	numempty[] = { CHAR_MAX, '\0' };
	...
		"",     	/* thousands_sep */
		numempty	/* grouping */

so the flag prints the number unchanged. The wide formatter now skips
' with the other flags before it hands the conversion to the host's
snprintf, as the narrow one does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:50:08 +00:00
milescoviello 7ad0736032 fix(libc): format positional arguments in the wide printf family
The wide formatter behind swprintf, vswprintf, wprintf and snwprintf_s
does not parse %n$ or *m$. It reads the position digits as a field
width, takes '$' for the conversion and fails, so on main
swprintf(buffer, 32, L"%2$d-%1$d", 1, 2) returns -1 with errno EINVAL
and an empty buffer. Localized format strings that reorder their
arguments this way print nothing.

FreeBSD formats wide output with __vfwprintf (vswprintf.c line 79),
which takes positions exactly as the narrow vfprintf does. FreeBSD 11.4
lib/libc/stdio/vfwprintf.c lines 635-652:

	case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		n = 0;
		do {
			n = 10 * n + to_digit(ch);
			ch = *fmt++;
		} while (is_digit(ch));
		if (ch == '$') {
			nextarg = n;
			if (argtable == NULL) {
				argtable = statargtable;
				if (__find_warguments (fmt0, orgap,
						       &argtable)) {

and GETASTER (lines 509-531) reads a *m$ width or precision from
position m without moving nextarg.

The wide formatter now numbers its arguments with the narrow
formatter's NumberedArgumentClasses and ArgumentPosition, run over an
ASCII copy of the format, so the same FreeBSD rules apply: a position
selects the argument, *m$ does not move it, and a conversion without a
position takes the argument after the previous one. Formats without a
position are formatted as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:50:08 +00:00
milescoviello 6a19442f12 fix(libc): start append-mode streams at the end of the file
fopen and freopen leave an "a+" stream where the host CRT puts it, at
the start of the file. On main, after fopen(file, "a+") on a 7-byte
file, ftell returns 0 and the first fgetc returns the first byte of the
file. FreeBSD seeks every append-mode stream to the end when it opens
it, so ftell returns 7 and a read before any fseek returns EOF. Code
that opens a log or save file with "a+" and tests ftell(f) == 0 to see
whether the file is new treats every existing file as empty.

FreeBSD 11.4 lib/libc/stdio/fopen.c (fopen), and the same lines in
lib/libc/stdio/freopen.c (freopen):

	if (oflags & O_APPEND) {
		fp->_flags2 |= __S2OAP;
		(void)_sseek(fp, (fpos_t)0, SEEK_END);
	}

lib/libc/stdio/flags.c sets O_APPEND for every mode that starts with 'a':

	case 'a':	/* open for appending */
		ret = __SWR;
		m = O_WRONLY;
		o = O_CREAT | O_APPEND;

fopen and freopen now seek a stream opened with an 'a' mode to the end
of the file, ignoring a failed seek as FreeBSD does. Writes still go to
the end through O_APPEND.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:50:07 +00:00
fablevoid c763a78b67 feat(relinker): split unaligned 256-bit stores for Rosetta
Rosetta 2 ends the process when an unaligned 256-bit store crosses into
a page the store may not write ("rosetta error: unexpectedly need to
EmulateForward on a synchronous exception") instead of raising the
fault. A store inside such a page, and a 128-bit store across one,
fault normally. The macOS write watch keeps watched pages read-only
between collections, so a guest that stores 32 bytes across the start
of a watched page ends the process.

--to-rosetta now lowers VMOVUPS, VMOVUPD and VMOVDQU with a 256-bit
memory destination to a stub that stores the low half with the same
instruction at VEX.L=0 and the high half with VEXTRACTF128 at the
operand plus 16, so each half faults like any other store. RIP-relative
operands are relocated from the instruction's place in the site. A
store whose upper half has no 32-bit displacement fails the conversion.
Aligned stores (VMOVAPS, VMOVAPD, VMOVDQA and the non-temporal forms)
cannot cross a page and are left alone.

Every store is lowered. A 4-byte store has no room for the jump to its
stub, so its stub also takes one neighbouring instruction. The
following one: a return ends the stub, a call pushes its original
return address and jumps, a jump or conditional branch is re-encoded
with a 32-bit displacement, and another 256-bit store is lowered in the
same stub. Otherwise the preceding one, unless it is a call, a jump, a
return or a trap. Register calls, LOOP, JRCXZ and branches with a
prefix that changes them do not move. When neither neighbour can move,
the store becomes a short jump to an island: a run of movable
instructions within reach is moved to its own stub, and the bytes it
frees hold the jump to the store's stub. A store with neither fails the
conversion.

The converter tests compare the halves with clang's encodings for base,
SIB, disp8 overflowing to disp32, disp32, RSP-relative, FS-absolute,
r13-based and RIP-relative operands, and check that aligned stores,
loads, register forms and masked stores are not split. They check the
stub of a short store followed by a return, a call (direct, with an
address-size prefix, and through a RIP-relative pointer), short, near
and RIP-relative jumps, short and near conditional branches and another
store; that a following register call, LOOP, JRCXZ, prefixed branch or
CLWB makes the store take the instruction before it; islands past
instructions already moved, a store that needs its own stub, a branch
target, a register call and the short-jump reach; and that a store with
no room fails.

PPSA12544: 55295 stores split in the executable, 278 of them in the
stub of the store before them; every module converts with none kept.

AI-assisted: yes
2026-10-12 02:48:33 +00:00
fma-rc e0eef6c57f
feat(pad): hold the sticks from the controller command file 2026-10-12 04:47:59 +02:00
Yassine 5959506bbd test(avplayer): link guest_avplayer with the shared runtime libraries
guest_avplayer_tests imports __cxa_throw from libc.prx, which is loaded
before libstdc++, but -static-libgcc gave it a private copy of
_Unwind_Resume. A failed Check threw through libc.prx's unwinder and the
landing pad of the test function resumed with the private one, so on
Linux every failure aborted in _Unwind_RaiseException_Phase2 instead of
printing its message from main. This is the unexplained Linux abort in
the intermittent guest_avplayer failures.

The test is now linked without the static runtime flags, as the AgcDriver,
Agc and VideoOut tests already are, so the unwinder comes from the same
library as __cxa_throw. A forced Check failure in TestPlayback aborted
before and now prints its message and exits with 1.

(cherry picked from commit fa5199cd8fef7f9c7ab9e83a441e15d16364a81d)
2026-10-12 02:47:43 +00:00
Dean 34a16b7f08
Merge pull request #4159 from MarcZX100/codex/fix-sampled-cache-fixture-4141
test(agc): keep sampled cache fixture registrations separate
2026-10-12 15:47:18 +13:00
Dean 2263cefe25
Merge pull request #3601 from Scramblrrrr/codex/legacy-sse-reciprocals
fix(relinker): lower legacy packed reciprocal register instructions
2026-10-12 15:43:20 +13:00
overlordxrz-source 4b378a251f feat(libSceRudp): implement sceRudpGetMaxSegmentSize 2026-10-11 22:43:17 -04:00
Dean 6253883dee
Merge pull request #3881 from gravelas/fix/libscejson2-object-find
feat(libSceJson2): implement Object::find, Object::iterator::operator-> and String::compare
2026-10-12 15:42:47 +13:00
Dean 438ee8a517
Merge pull request #3652 from orishamir/fix/pad-analog-triggers
fix(pad): keep partial L2/R2 values from a controller
2026-10-12 15:42:14 +13:00
Dean f49f95873c
Merge pull request #3969 from hugodearaujo/fix/user-age-level
fix(libSceUserService): report an unrestricted age level
2026-10-12 15:34:36 +13:00
Dean d1758a91c8
Merge pull request #3494 from babyhuey/carry/pthread-attr-scope-3377
feat(libkernel): implement pthread_attr_getscope, setscope, getinheritsched and getstackaddr
2026-10-12 15:33:56 +13:00
Dean c2fdb9c71c
Merge pull request #2902 from oneandonlydean/carry/libkernel-sysctl-sdk-version
feat(libkernel): support kern.sdk_version in sysctlbyname
2026-10-12 15:33:29 +13:00
Scramblrrrr 29a843579d test(memory): query host holes beside warm collect memos 2026-10-11 23:27:02 -03:00
Karan Vora 4a4ec4c62c perf(shader): keep wave32 EXEC and VCC lane bits without a ballot round trip
In wave32 a compare that wrote vcc_lo kept only the ballot word and rebuilt the
lane's bit from it as (word >> lane) & 1, and every read of vcc_lo as a lane
mask (v_cndmask, carry-in) did the same. s_*saveexec_b32 and the 32-bit scalar
logic ops and s_mov_b32 that write exec_lo or vcc_lo also rebuilt the lane bit
from the new word. Wave64 already kept the lane bits.

Every writer keeps Vcc equal to the lane's bit of VccLo and Exec equal to the
lane's bit of ExecLo, so in wave32:
- a compare into vcc_lo sets Vcc to the compared value, and reading vcc_lo as
  a mask returns Vcc;
- s_*saveexec_b32 combines the old Exec with the source's lane bit, and tags
  the saved mask in the destination SGPR with the old Exec;
- s_and/or/xor/not/andn2/orn2/nand/nor/xnor_b32 and s_mov_b32 that involve
  exec_lo or vcc_lo combine the sources' lane bits the way sU64Mask does for
  the 64-bit forms, and tag an SGPR destination.
The words are still computed as before for scalar reads, SCC and branches;
where nothing reads them they are dead.

agc_driver_wave32_exec_lane_bits runs a wave32 program with v_cmp into vcc_lo,
v_cndmask, s_and_saveexec_b32 and exec restores through s_or_b32 and s_mov_b32,
checks every lane, and checks that its SPIR-V has no subgroup ballot left.
2026-10-11 22:23:44 -04:00
hypermist 8083dd1114 perf(agc): sort guest buffer regions through indices before merging them
UploadPrepare sorted the build's Region objects themselves, each a few
hundred bytes of vectors and shared pointers, and grew the merged list
without reserving it, moving every region many times per resource build.
Sorting an index array and reserving the merged list moves each region
once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo
2026-10-12 15:08:34 +13:00
Dean Galvin 572e9d9f78 test(agc): word the tessellation and oversized dispatch skips as device limitations, as check_skips expects 2026-10-12 15:06:12 +13:00
Achraf Reyani 6b2432875d fix(agc): accept a linear 2D texture whose DEPTH holds its default pitch
On GFX10.3 the DEPTH field of a 1D or 2D non-array linear T# carries the
row pitch minus one (Mesa's ac_descriptors.c sets it for custom pitches,
which must be multiples of 256 bytes). A single-level, uncompressed 2D
linear texture whose DEPTH equals its default 256-byte-aligned pitch now
decodes as that 2D texture; any other pitch still throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:04:50 +09:00
Dean ceb342b947
Merge pull request #4240 from oneandonlydean/up4/fix-check-skips-packed-float16
test(agc): report the packed f16 native skip as a device limitation, as check_skips expects
2026-10-12 15:00:56 +13:00
MarcZX100 ce9fc689b7 docs(libkernel): record Windows directory name limit 2026-10-12 01:51:35 +00:00
Dean Galvin 20b801b7e8 test(agc): report the packed f16 native skip as a device limitation, as check_skips expects 2026-10-12 14:51:21 +13:00
ArjenS-LA b41c0b3da9 fix(libkernel): reject oversized Windows directory entry names
(cherry picked from commit b0e0c1c4bfd1487047873663115a94a46987b831)
2026-10-12 01:51:01 +00:00
milescoviello 589de27c17 fix(libc): accept the fdopen modes FreeBSD accepts
fdopen only took a fixed list of 15 mode strings and failed with EINVAL
for any other, so "rt", "r+t", "re", "rbe" or "rw" gave NULL. FreeBSD's
fdopen parses the mode with __sflags (lib/libc/stdio/flags.c): after
r, w or a it takes b, +, x, e and v and stops at the first other
character ("default: known = 0;"), and only a bad first character or x
on a read-only mode fail with EINVAL. fopen and freopen already parse
modes this way through ParseFileMode (#2033).

fdopen now uses ParseFileMode as well and passes the host its normalised
mode without x, which FreeBSD's fdopen ignores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:50:11 +00:00
milescoviello 30d1e85283 fix(libScePosixForWebKit): use FreeBSD's gai_strerror message texts
gai_strerror returned its own wording for most codes, so a resolver
failure was described with text FreeBSD's libc does not use: EAI_NONAME
(8) gave "Name or service not known" instead of "hostname nor servname
provided, or not known", EAI_BADFLAGS (3) "Invalid flags" instead of
"Invalid value for ai_flags", and an unknown code "Unknown address
resolution error" instead of "Unknown error". Twelve of the fifteen
texts differed.

FreeBSD 11.4, lib/libc/net/gai_strerror.c:

	static const char *ai_errlist[] = {
		"Success",					/* 0 */
		"Address family for hostname not supported",	/* 1 */
		"Temporary failure in name resolution",		/* EAI_AGAIN */
		"Invalid value for ai_flags",			/* EAI_BADFLAGS */
		"Non-recoverable failure in name resolution",	/* EAI_FAIL */
		"ai_family not supported",			/* EAI_FAMILY */
		"Memory allocation failure", 			/* EAI_MEMORY */
		"No address associated with hostname",		/* 7 */
		"hostname nor servname provided, or not known",	/* EAI_NONAME */
		"servname not supported for ai_socktype",	/* EAI_SERVICE */
		"ai_socktype not supported", 			/* EAI_SOCKTYPE */
		"System error returned in errno", 		/* EAI_SYSTEM */
		"Invalid value for hints",			/* EAI_BADHINTS */
		"Resolved protocol is unknown",			/* EAI_PROTOCOL */
		"Argument buffer overflow"			/* EAI_OVERFLOW */
	};
	...
	if (ecode >= 0 && ecode < EAI_MAX)
		return ai_errlist[ecode];
	return "Unknown error";

The table and the unknown-code text now match, as 5830d8e44 did for
strerror.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:49:40 +00:00
milescoviello cba3b5a8b3 fix(libkernel): accept SOCK_NONBLOCK and SOCK_CLOEXEC in socket
socket only took a type of exactly SOCK_STREAM or SOCK_DGRAM, so a type
with SOCK_NONBLOCK (0x20000000) or SOCK_CLOEXEC (0x10000000) set failed
with EPROTONOSUPPORT, although socketpair already accepted both.

FreeBSD strips both flags before creating the socket (sys/kern/
uipc_syscalls.c, kern_socket: "if ((type & SOCK_CLOEXEC) != 0) { type
&= ~SOCK_CLOEXEC; oflag |= O_CLOEXEC; }" and the same for SOCK_NONBLOCK
with FNONBLOCK), and makes the new socket non-blocking with
"fo_ioctl(fp, FIONBIO, &fflag, ...)".

socket now does the same as socketpair: it creates the socket from the
plain type and, with SOCK_NONBLOCK, switches it to non-blocking.
SOCK_CLOEXEC needs nothing more, since a guest never executes another
program.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:48:40 +00:00
milescoviello 910363657d fix(libc): count the whole string in mbstowcs with a null destination
mbstowcs, and libSceAmpr's copy of it, counted at most n characters
when the destination was NULL, so the usual sizing call
mbstowcs(NULL, s, 0) returned 0 and mbstowcs(NULL, s, 1) returned 1 for
a three-character string. A caller that sizes its buffer that way got a
buffer too small for the string and no terminator.

POSIX says that with a null pwcs mbstowcs "shall return the length
required to convert the entire array regardless of the value of n", and
FreeBSD does that: lib/libc/locale/mbstowcs.c passes SIZE_T_MAX as the
source limit, and the C locale's _none_mbsnrtowcs (none.c) returns the
distance to the terminating NUL when "dst == NULL".

With a null destination, SonyMbstowcs now returns the length of the
whole string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:47:11 +00:00
Dean d371ed3076
Merge pull request #4200 from winstrex/fix/host-entropy
fix(libs): take guest entropy from the host OS instead of std::random_device
2026-10-12 14:42:53 +13:00
Dean 695b8e552c
Merge pull request #4169 from oneandonlydean/up4/fix-mprotect-stack-bound
fix(libkernel): reject mprotect of host memory that is not a guest thread stack
2026-10-12 14:41:35 +13:00
Dean d0ca839cc9
Merge pull request #4057 from jweidenh/codex/vector-window-stage-inputs
fix(recompiler): include implicit inputs in relative vector windows
2026-10-12 14:30:23 +13:00
Karan Vora d759a43ae5 perf(shader): search a bindless image table once per access
EmitImage selects the table slot of a bindless image before it branches over
the image's runtime modes, and EmitImageMode then searched the table again in
every mode arm. Each search is a binary search of dependent flattened_srt
loads, so every bindless sample ran two. The mode arms now take the selection
EmitImage already made; the modes copy the base image, so the mapping offset,
root and iteration count the search reads are the same.
2026-10-11 21:22:52 -04:00
Nixitov 7d9966a8ee feat(libc): implement __divti3
Kart PS5 (PPSA99611) imports __divti3 and stops at start-up on main. The guest has no signed 128-bit division; add it alongside __udivti3, dividing the magnitudes and negating the quotient, and throwing on a zero divisor like the unsigned routine.
2026-10-12 03:22:38 +02:00
Dean 34ba918bc3
Merge pull request #4177 from oneandonlydean/up4/fix-registered-workgroup-sync
test(agc): read lane 63 of the vertex index in the registered workgroup fixture
2026-10-12 14:22:30 +13:00
pallp 4b125c0ca5 fix(savedata): fill the search infos of sceSaveDataDirNameSearch
SaveDataDirNameSearchResult.infos points at an array the title reads one
entry per returned directory name, but the search never wrote it, and
SaveDataSearchInfo was declared as 128 opaque bytes. A title that asks for
the infos read whatever its buffer held.

SaveDataSearchInfo is now the 48-byte record shadPS4 declares as
OrbisSaveDataSearchInfo (blocks, free blocks, 32 reserved bytes), and the
search fills one per returned name. Every native save reports
SAVE_DATA_BLOCKS_MAX blocks, as sceSaveDataGetMountInfo and the block sort
keys already assume, so both counts are SAVE_DATA_BLOCKS_MAX and the
reserved bytes are zero.

guest_savedata_search_tests checks the two records, their zero reserved
bytes and that the search writes nothing past them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFVE5WbaUJ2vyj8NAW44CS
2026-10-12 02:18:33 +01:00
Scramblrrrr b45232dda6 test(memory): handle Windows layouts without arena host holes 2026-10-11 22:18:20 -03:00
fma-rc b843b16a0a
fix(libSceSystemService): answer parameter 400 with the console language 2026-10-12 03:18:00 +02:00
Nesyth d9fbaf767c fix(agc): accept a CB metadata pass beside depth state without depth or stencil planes 2026-10-12 03:14:12 +02:00
saxopa cded9ba8c3 fix(relinker): accept RELATIVE relocations against a zero-value section symbol
OpenOrbis create-fself adds one to the symbol index of every relocation it
copies from .rela.dyn, so each R_X86_64_RELATIVE entry of a homebrew built
with the OpenOrbis toolchain names symbol 1, a local STT_SECTION symbol with
value 0. FreeBSD rtld computes RELATIVE as base + addend without reading the
symbol. The pipeline, the code analysis and the strict filter now accept
index 0 or a STT_SECTION symbol with value 0, and still throw for any other
symbol. The relocation is written with symbol index 0, where the pipeline
previously dropped RELATIVE entries with a nonzero index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:12:02 +02:00
winstrex 8f9efc25f2 fix(libs): take guest entropy from the host OS instead of std::random_device
std::random_device in libstdc++ reads RDSEED on x86 Linux. On an AMD
EPYC 9V45 (Zen 5) CI runner its 32-bit results repeat about 130 times
in 65536 draws, so guest_posix_random fails. libc now exports
HostEntropy_nid_no_patch, which uses getentropy (rand_s on Windows) and
throws when the OS cannot provide entropy. arc4random, arc4random_buf,
sceRandomGetRandomNumber, /dev/random and /dev/urandom reads,
std::_Random_device and sceKernelUuidCreate use it, and the arc4random
and random device TechnicalDebt entries say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:07:49 -03:00
jweidenh 38b05f4868 fix(agc): initialize every sparse buffer copy hole 2026-10-11 21:06:02 -04:00
jweidenh 8404d62be9 test(agc): reproduce stale bytes in sparse buffer holes 2026-10-11 21:06:02 -04:00
Scramblrrrr 875d730116 fix(agc): report sparse CPU copy spans after allocation 2026-10-11 21:54:42 -03:00
Dean Galvin 8938a257f2 test(agc): read lane 63 of the vertex index in the registered workgroup fixture
The fixture read lane 63 of v0, which the program never writes. Since #3546 a wave64 vertex program on a narrower host subgroup builds that read as 0, so the synchronous registration the test expects to fail succeeds. v5 holds the vertex index, which is not 0 in lanes 32-63, so the read still throws.
2026-10-12 13:44:23 +13:00
Kikoarl d906ee2f6d test(agc): add unit test for copied writer indirect overlap disambiguation 2026-10-12 02:42:14 +02:00
Oxide 1-6 3df53d9296
fix(shader): preserve integer narrowing in constant folding
Remove unsafe U16/U8 round-trip cancellation and cover nonconstant, immediate, bitcast and dead-code cleanup paths with Release-active IR regressions.
2026-10-12 06:08:56 +05:30
screamm 1b4baaee27 fix(memory): exclude arena host holes from every write-tracking query
On Windows agc_write_tracking has failed since #3594 with

    write tracking test failed: an unwatched range reads as not stored over

from the check in CheckSharedBlock:

    if (!Watched(outside, unwatched.size())) Require(StoredOver(outside, unwatched.size(), TrackerGeneration()), "an unwatched range reads as not stored over");

The host stack array lies in a host hole of the guest arena. #3594 made
Watched, collectWrites, UnchangedSince, UnchangedSinceAll and storeOwn
reject ranges overlapping such holes, but StoredOver, MarkWritten,
WrittenSince, ChangedBlocks and ImportWatched still accepted them through
WriteTracker::covers(), so StoredOver proved a range not stored over while
Watched called it unwatched (#4087).

The exclusion now lives in WriteTracker::covers() on Windows, which every
query already asks, and the per-function checks are removed. Host holes
are padded to the allocation granularity and the tracker blocks are 64 KiB
from the arena base, so no block is shared between a hole and arena
memory, and ranges outside the holes get the same answers as before.

A new case enumerates the arena for a host hole and checks every query
against it; on the previous code StoredOver, MarkWritten, StoreOwnBytes,
WrittenSince and ChangedBlocks fail it.

Fixes #4087

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 21:36:46 -03:00
Scramblrrrr ef218ef928 test(agc): distinguish GPU depth from reused storage bytes 2026-10-11 21:29:59 -03:00
Scramblrrrr b9b83cef2b style(graphics): follow the code comment convention 2026-10-11 21:29:25 -03:00
Scramblrrrr 4de5726d32 fix(graphics): distinguish reused memory from depth storage aliases 2026-10-11 21:29:25 -03:00
Dean 7a84b22267
Merge pull request #4131 from oneandonlydean/up4/fix-stored-over-unwatched
fix(agc): report arena host holes as stored over on Windows
2026-10-12 13:29:17 +13:00
Archit Dewan 5eb22de16d fix(relinker): reject empty positional paths 2026-10-11 20:28:56 -04:00
MarcZX100 c87c8c229b test(agc): keep sampled cache fixture registrations separate 2026-10-12 00:12:50 +00:00
hugodearaujo 0b7e4ddf9f fix(libkernel): join the calling thread and create from an unset attribute as the console does
On a PS5 (firmware 13.60) scePthreadJoin on the calling thread returns
EDEADLK and scePthreadCreate with a zeroed attribute creates a thread
with the default attributes. Here both threw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:09:08 -03:00
Celegans12 364d7cf29f fix(shader): match half-wave reductions over relatively addressed vector registers
A program that uses v_movrels_b32 or v_movreld_b32 keeps every vector
register from the lowest relatively addressed one up in a per-invocation
window array, so its plain register accesses become LoadVectorWindow and
StoreVectorWindow. The half-wave reduction matcher followed only SSA values,
so a wave64 scan, v_permlanex16_b32 join and lane 31/63 read through that
array threw that lane 63 is outside the 32-lane host subgroup.

The matcher now reads a window load at a constant slot as the value of the
last store to that slot earlier in its block, unless a store at a runtime
slot lies in between; each invocation owns its array, so that is the value
the load returns. A store in another block, or a v_movreld_b32 at a runtime
M0 in between, still throws. This was the only refused lane 32-63 read left
among Ghost of Yotei's wave64 graphics programs (one pixel program).
2026-10-12 02:07:50 +02:00
hugodearaujo b9b5bcc190 fix(libkernel): return the console's errors from the SCE mutex calls
On a PS5 (firmware 13.60) the SCE mutex attribute calls return EINVAL
for a null or uninitialized attribute, scePthreadMutexattrSetprotocol
accepts 0 to 2, scePthreadMutexInit takes an uninitialized attribute as
the default one, and destroying a destroyed mutex returns EINVAL. Here
these threw, including for the priority protection protocol.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:06:55 -03:00
Avijit Singh fc7a9650f9 style(agc): remove unnecessary shutdown explanation
Keep the tracker initialization fix without an explanatory code comment or technical-debt entry, as requested in review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 05:32:09 +05:30
hugodearaujo 2446a2648a fix(libkernel): return the console's errors from the scePthreadAttr calls
On a PS5 (firmware 13.60) the scePthreadAttr setters and getters return
EINVAL for a null or uninitialized attribute and for a null output,
ENOTSUP for a policy other than SCHED_FIFO and SCHED_RR, an inheritance
other than explicit and inherit, and a priority outside 256 to 767, and
EINVAL for an invalid detach state. Here they threw, or stored any
policy, inheritance and priority.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:59:17 -03:00
eljackjoestar-cmd fded8a7e7f fix(shader): prove masked writes through guarded first-lane reads 2026-10-12 03:57:04 +04:00
Kikoarl a057eede19 perf(agc): disambiguate direct GPU writes from copied write-backs in indirect draws 2026-10-12 01:53:33 +02:00
Dean Galvin 5b1868d23d fix(libkernel): reject mprotect of host memory that is not a guest thread stack
The Windows path from #3788 changed the protection of any committed private host region outside the guest registry, including a range crossing a guest stack's lower bound. Ranges inside a live guest thread stack keep the path from #2982.
2026-10-12 12:50:24 +13:00
lorkydey f88be06af2 fix(libkernel): resolve getlogin_r from the effective host account 2026-10-12 01:39:07 +02:00
lorkydey a4502cd4bd feat(libkernel): implement getlogin_r using the host login name 2026-10-12 01:39:07 +02:00
Dean Galvin 5864ee5839 fix(agc): report arena host holes as stored over on Windows
StoredOver still read block stamps for a range in a host region inside the guest arena interval, which Watched reports as unwatched since #3594.
2026-10-12 12:38:06 +13:00
xXPBSXx 2a7b38ab75 fix(libSceAgc): write the KytyPS5 workload packets and return null for unregistered streams
sceAgcDcbSetWorkloadsActive writes an 18-dword IT_NOP packet (stream id, 64-bit workload mask) and sceAgcDcbSetWorkloadComplete a 12-dword one (stream id, workload id, 64-bit clear mask), following KytyPS5. Both return null for a null buffer, an unregistered or out-of-range stream, a workload id above 63, and for active a duplicate id or a count of 0 or above 63. sceAgcDriverRegisterWorkloadStream and sceAgcDriverUnregisterWorkloadStream now record the stream ids the DCB calls check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 01:37:56 +02:00
Claude c35d05395d
fix(libc): reject 16-bit wide conversions in sscanf_s and after the ' flag on Linux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 23:37:17 +00:00
xXPBSXx 45fcf734ab fix(libSceAgc): emit NOP packets for the DCB workload calls
sceAgcDcbSetWorkloadsActive and sceAgcDcbSetWorkloadComplete threw. They now write a plain two-dword NOP and keep no workload state.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 01:36:51 +02:00
hugodearaujo 78abb2b46a fix(libSceUserService): report the console's default accessibility settings
On a PS5 (firmware 13.60) a user with every accessibility setting at
its default reads chat transcription 0, press-and-hold delay 0, trigger
effect 1, vibration 1, zoom 0 and zoom follow focus 1; all six read 0
here. A user who is not logged in returns 0x80960009 with or without an
output, as sceUserServiceGetAgeLevel does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:35:58 -03:00
PrintOrb 4680a52c1e fix(libkernel): return positioned descriptor errors without CRT reports 2026-10-11 18:35:17 -05:00
Simon 2fd05f47e2 feat(libSceNpWebApi2): export sceNpWebApi2AddWebTraceTag
PPSA33016 imports sceNpWebApi2AddWebTraceTag (NID MgsTa76wlEk), and no
library exported it, so the loader stopped before the title started.
The title does not call it at start-up or in play, so the export throws
like the other unimplemented functions.
2026-10-12 01:30:54 +02:00
Dean bca7a29d25
Merge pull request #4021 from Mouhand-Kaddo/fix/windows-select-host-poll
fix(libkernel): restore Windows select build for Demons Souls testing
2026-10-12 12:30:30 +13:00
ethan 63a27648a8 fix(relinker): resolve EIP-relative imports in strict filter 2026-10-11 16:24:12 -07:00
jdmagic d5805fb3e4 fix(libkernel): setsockopt sets options of libSceNet sockets
A title creating a socket with sceNetSocket sets its options with the BSD
setsockopt, which looked the descriptor up only among libkernel's own
sockets and returned EBADF. libSceNet now registers an option setter with
libkernel, as it does for close and select, and accepts SO_REUSEADDR,
SO_BROADCAST, SO_SNDBUF and SO_RCVBUF like libkernel's own sockets.

PPSA01289 (Sackboy: A Big Adventure) sets SO_BROADCAST on its UDP P2P
socket this way in UIpNetDriver::InitBase. The failure made every listen
fail, and the engine travelled back to its default map with ?closed,
reloading it about every two seconds behind the loading screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:23:24 -04:00
jdmagic 5d14cd02ff fix(libSceNet): failures also set libkernel's errno
libSceNet stored its errno only in its own slot (sceNetErrnoLoc). Titles
that use the BSD socket model read errno after a libSceNet call, as the
console's libSceNet calls are kernel calls that set it; shadPS4 mirrors its
net errno into the kernel errno the same way (SetKernelErrnoHook).

PPSA01289 (Sackboy: A Big Adventure) reads errno through Unreal's
GetLastErrorCode after sceNetRecvfrom. It never saw EWOULDBLOCK, so
UIpNetDriver::TickDispatch kept receiving and the game thread never left
its first networked frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:23:24 -04:00
jdmagic 12b18af550 fix(libkernel): close() closes libSceNet sockets
A libSceNet socket is a kernel descriptor on the console, so titles close it
with close(). libSceNet keeps its sockets in its own table, and libkernel's
close passed their numbers to the CRT, which reported an invalid parameter
and left the socket open. libSceNet now registers a closer with libkernel,
as it registers its poller for select. PPSA01289 (Sackboy: A Big Adventure)
closes its P2P socket this way each time it tears its network session down,
leaking one open socket per attempt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:23:24 -04:00
jdmagic 22827bf6ad fix(libSceNet): sceNetEpollControl takes 2 as MOD and 3 as DEL
sceNetEpollControl used Linux's EPOLL_CTL numbering (1 ADD, 2 DEL, 3 MOD).
The SCE values are 1 ADD, 2 MOD, 3 DEL (shadPS4 net_types.h,
ORBIS_NET_EPOLL_CTL_*). A title removing a socket with op 3 and a null
event got EINVAL, and op 2 deleted the registration it meant to modify.
PPSA01289 (Sackboy: A Big Adventure) removes its UDP socket from its epoll
this way before closing it, every time its network session is torn down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:23:23 -04:00
jweidenh 5ec6cff3fa fix(recompiler): include implicit inputs in relative vector windows 2026-10-11 19:23:00 -04:00
jweidenh e4575c723e test(recompiler): keep vector window fixtures observable 2026-10-11 19:23:00 -04:00
jweidenh c0c86deeb8 test(recompiler): cover implicit inputs in relative vector windows 2026-10-11 19:23:00 -04:00
xXPBSXx 35a6df818f Merge remote-tracking branch 'upstream/main' into fix/export-ppsa30601-imports
# Conflicts:
#	core/libs/prx/libSceJson2/Export.cpp
#	docs/dev/TechnicalDebt.md
2026-10-12 01:19:36 +02:00
xXPBSXx 50ca599251 Merge remote-tracking branch 'upstream/main' into fix/ces-cp1251-profile
# Conflicts:
#	docs/dev/TechnicalDebt.md
2026-10-12 01:17:20 +02:00
hugodearaujo 802ec551c2 fix(libSceUserService): answer sceUserServiceGetUserName as the console does
On a PS5 (firmware 13.60) a null name returns INVALID_ARGUMENT first,
then a user id the console does not know returns 0x80960105 whatever
the buffer, and a buffer shorter than 17 bytes is zeroed before
BUFFER_TOO_SHORT is returned. Here an unknown user returned
INVALID_ARGUMENT and a short buffer was left untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:12:43 -03:00
virp-mta 8b04156bfd fix(libkernel): return EDESTADDRREQ for send and sendto on unconnected UDP sockets 2026-10-12 03:12:34 +04:00
Yunus Shaikh 1b009e1879 fix(libc): subtract negative times in difftime on Windows
difftime and libc_difftime passed their arguments to the host CRT.
UCRT's _difftime64 returns 0 and sets errno to EINVAL when either
argument is negative (common_difftime in ucrt/time/difftime.cpp), so
on Windows difftime(0, -1) returned 0 instead of 1 and every
difference involving a time before 1970 was 0. C17 7.27.2.2 defines
the result as time1 - time0, and FreeBSD 11's difftime
(contrib/tzcode/stdtime/difftime.c) and glibc on the Linux build
compute it for any arguments.

Subtract the smaller time from the larger as uint64_t, which cannot
overflow, convert the difference to double and negate it when time1
is the smaller one, as FreeBSD and glibc's fallback path do. The
result is time1 - time0 rounded once to double on both hosts.
difftime now forwards to libc_difftime like the other aliases in the
file.
2026-10-11 16:12:25 -07:00
krishnaraya e5f943e3b3 fix(shader): keep the output modifier of the f16 min3, max3, med3 and div_fixup ops
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:10:15 -04:00
nyavana 67cdc9edcc docs(relinker): correct help and exit-code usage
Document --help output and status, distinguish no-argument errors, and include help in the successful exit code description.

AI-assisted: yes (OpenAI Codex).
2026-10-11 16:09:56 -07:00
Yunus Shaikh 7cc5698094 fix(libc): format years before 1900 in asctime on Windows
asctime passed the guest tm to the host CRT. UCRT's asctime returns
null and sets errno to EINVAL when tm_year is negative or tm_mday is
past the end of the month (common_asctime_s in ucrt/time/asctime.cpp),
so on Windows asctime of any time in the years 1000 to 1899, which
gmtime converts, or of February 29 in a common year returned null.
C17 7.27.3.1 defines the text for every year from 1000 to 9999 when
each member is in its normal range (tm_mday 1 to 31), and glibc on
the Linux build and FreeBSD 11's asctime
(contrib/tzcode/stdtime/asctime.c) print it.

Format the text with the C17 algorithm's format into a thread-local
buffer that fits any member values. As in glibc and FreeBSD, a
weekday or month outside its range is printed as ???, and the year is
computed in 64 bits.
2026-10-11 16:08:53 -07:00
Adrià bab7b32852
Merge pull request #3772 from MrMha/perf/relinker-call-index
perf(relinker): use a flat sorted call-site index
2026-10-12 01:05:45 +02:00
Yunus Shaikh 433bf1ebc2 fix(libc): map _Towctrans descriptors 1 and 2 to lower and upper case
_Towctrans passed the guest's descriptor to the host towctrans.
Dinkumware's <wctype.h> (xwcc.h) defines towlower(wc) as
_Towctrans(wc, 1) and towupper(wc) as _Towctrans(wc, 2), the values
FreeBSD's wctrans.c also uses for "tolower" and "toupper". UCRT reads
1 as toupper and other nonzero values as tolower, so on Windows
towlower(L'A') returned L'A' and towupper(L'a') returned L'a', while
towlower(L'a') returned L'A'. The host wint_t is 16 bits there, which
also turned WEOF into 0xffff. glibc's wctrans_t is a pointer to a
table that towctrans reads, so on Linux descriptor 1 or 2 is
dereferenced as an address.

_Towctrans now takes the guest's 32-bit wint_t and size_t descriptor.
1 and 2 map 0..255 through the C locale tables behind _Getptolower and
_Getptoupper and return other values unchanged. Any other descriptor
sets errno to EINVAL and returns wc unchanged, as FreeBSD's
towctrans_l does.
2026-10-11 16:05:26 -07:00
jweidenh 72d5b8ce90 fix(relinker): ignore no-op relocations in guest modules 2026-10-11 19:02:06 -04:00
Yunus Shaikh f7a85491ef fix(libSceNet): report EAGAIN when a datagram receive times out on Windows
With SO_RCVTIMEO set, Winsock fails a receive that waits that long with
WSAETIMEDOUT, which native_error turned into ETIMEDOUT (60). sceNetRecv,
sceNetRecvfrom and sceNetRecvmsg on a datagram socket therefore failed
with 0x8041013C on Windows, where FreeBSD's sbwait returns EWOULDBLOCK
(35) to soreceive, Linux returns EAGAIN, and POSIX (XSH 2.10.16)
requires EAGAIN or EWOULDBLOCK when no data was received.

A datagram socket has no connection that can time out, so WSAETIMEDOUT
there only means that the receive timeout the guest set has expired:
report EAGAIN. Stream sockets keep ETIMEDOUT, since Winsock leaves a
connection in an indeterminate state after a timeout; TechnicalDebt
records that gap and the one for SO_SNDTIMEO.
2026-10-11 16:01:51 -07:00
hugodearaujo 65b6a4729b fix(libkernel): accept only the solo scheduling values the console accepts
On a PS5 (firmware 13.60) scePthreadAttrSetsolosched and
pthread_attr_setsolosched_np accept only 0 and 16; every other value
returns ENOTSUP and keeps the stored one. The SCE set and get calls
return EINVAL for a null or uninitialized attribute instead of throwing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:01:44 -03:00
Gustavo Ariel Gamarra Rojas a70ec3946d feat(agc): store the dumped storage images at each flip
An image whose results stay on the GPU is never written back, so
APS5_DUMP_STORAGE saw nothing; APS5_STORE_AT_FLIP=1 stores every pending
image and ran a 4 GB device out of memory at 3840x2160. The selected
images alone are now stored at each flip.
2026-10-11 19:59:42 -03:00
Gustavo Ariel Gamarra Rojas f2d6986741 feat(agc): select storage dumps by shape and dump every layer
APS5_DUMP_STORAGE also takes <width>x<height>x<layers>[:<format>], for
images whose address changes from run to run (a title's 32x32x32
color-grading LUT), and the dump holds the first mip of every layer or
3D slice instead of the first one only.
2026-10-11 19:59:35 -03:00
Yunus Shaikh 0245ba7d88 fix(libc): open fopen streams with delete sharing on Windows
fopen opened its stream with _wfopen, which shares read and write
access but not delete access. While the guest held a stream open,
rename of its file failed with EIO and remove with EBUSY. POSIX rename
and remove work on open files, as on Linux and FreeBSD, and since
#3677 the descriptors sceKernelOpen returns share delete access.

fopen now creates the handle with CreateFileW sharing read, write and
delete, with the access and creation disposition of the mode, and
wraps it with _open_osfhandle and _wfdopen, keeping append mode. A
failed CreateFileW sets errno through the error mapping #3677 added to
libkernel's NativeOpen, which moves to libc as
WindowsOpenError_nid_no_patch so that both use it. freopen still
reopens through _wfreopen; TechnicalDebt records it.
2026-10-11 15:56:20 -07:00
pushkarreddyy 726e773417 feat(libkernel): support kern.sdk_version in sysctlbyname 2026-10-12 11:53:41 +13:00
Alex de54527a8b fix(shader): keep f32 denormals in compares when denormals are kept
With the f32 denormal field of FLOAT_MODE set to keep, v_cmp_X_f32 and
v_cmpx_X_f32 read a denormal operand as zero: NVIDIA, RADV and lavapipe
all flush denormals in their float compares. Compare the operands as
sign-magnitude integers instead, with NaN handled apart. Compares with
flushed denormals are unchanged. This matches RDNA2 (gfx1036) on 256
operand pairs per opcode, with f32 denormals kept and flushed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 18:51:37 -04:00
jweidenh ecd4e90628 fix(libc): preserve the guest ABI for array callbacks 2026-10-11 18:51:28 -04:00
Adrià 325e0a8bdd
Merge pull request #3741 from jweidenh/codex/optimized-pipeline-readback
test(agc): verify graphics output after optimized pipeline binding
2026-10-12 00:50:45 +02:00
Adrià 22cecd5aac
Merge pull request #3779 from pushkarreddyy/feat/libkernel-sysctl-pathname-hw-physmem
feat(libkernel): handle sysctl queries for pathname, physmem and cacheline size
2026-10-12 00:48:35 +02:00
hugodearaujo 7b5ac83a2a fix(libkernel): destroy rwlocks the way the console does
On a PS5 (firmware 13.60) destroying a rwlock returns 0 even while it
is held, and leaves 1 in the handle; every later call on that handle
returns EINVAL until it is initialized again. A zero handle is
initialized on first use by the scePthreadRwlock calls too. Here a held
rwlock returned EBUSY, a destroyed handle became null and was silently
re-created by the next POSIX call, and the scePthreadRwlock calls threw
on a zero handle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:48:33 -03:00
kallmek3nny 5fd0e261c9 fix(aio): use precise polling sleep 2026-10-11 18:48:18 -04:00
hugodearaujo 3ba4751f98 fix(libkernel): report the console's scheduling priority range
On a PS5 (firmware 13.60) sched_get_priority_max returns 767 and
sched_get_priority_min 256 for SCHED_FIFO and SCHED_RR; the two were
swapped. Every other policy, SCHED_OTHER included, returns -1 with
EINVAL instead of a range or a host exception.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:47:18 -03:00
ethan 0a324d8ccb fix(relinker): resolve .suprx guest module aliases 2026-10-11 15:45:27 -07:00
Adrià ba08a1582a
Merge pull request #3876 from CnRJay/feat/savedata-convert
feat(savedata): implement sceSaveDataConvert
2026-10-12 00:43:58 +02:00
Adrià f9905068b7
Merge pull request #3730 from MarcZX100/codex/voiceqos-end-3331
feat(libSceVoiceQoS): implement sceVoiceQoSEnd
2026-10-12 00:42:41 +02:00
Adrià 6dbc0ea66a
Merge pull request #3829 from YossiYad/carry/agc-vieBRwlh1Lw
feat(libSceAgc): implement the vieBRwlh1Lw interpolant mapping update
2026-10-12 00:39:58 +02:00
Kikoarl 567898cd58 feat(libSceSysmodule): register libSceVoiceChat module ID (0x114) 2026-10-12 00:39:28 +02:00
Adrià 3905e7e2c9
Merge pull request #3827 from CouchRiv/fix-shader-combined-cvt-i16-f16-omod
fix(shader): accept output modifiers on v_cvt_i16_f16 and ignore them as the hardware does
2026-10-12 00:39:20 +02:00
PrintOrb 5c19601a12 fix(videoout): require bundled SDL XRandR support on Linux 2026-10-11 17:36:12 -05:00
Adrià 2c884140a5
Merge pull request #3721 from MarcZX100/codex/content-export-sessions-3374
feat(libSceContentExport): implement export sessions
2026-10-12 00:35:54 +02:00
Adrià 6426baa107
Merge pull request #3691 from MarcZX100/fix/sem-timedwait-available-first
fix(libkernel): handle available sem_timedwait counts first
2026-10-12 00:35:17 +02:00
Claude 36c78ba143
fix(relinker): report the ModRM of 3DNow! instructions in decoded instruction info
DecodeInstruction did not treat 0F 0F as having a ModRM byte, so a
RIP-relative 3DNow! operand was not reported to the analyses and the
--to-intel stub relocation that read HasRipRelativeDisp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-11 22:34:39 +00:00
Mouhand Kaddo ac4954c6e3 fix(libkernel): guard Unix host polling in Windows select 2026-10-12 02:34:11 +04:00
xXPBSXx 859d0b1e63 fix(exports): also export sceHmd2GetFieldOfView
main has sceHmd2GetFieldOfViewWithoutHandle only; PPSA07411 imports sceHmd2GetFieldOfView.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:33:41 +02:00
Adrià dd1cf5cb9d
Merge pull request #3771 from yunusshaikh7/fix/savedata-dir-name-search-sort
fix(savedata): sort sceSaveDataDirNameSearch results by the requested key and order
2026-10-12 00:30:16 +02:00
Adrià ae7dbfa9cb
Merge pull request #3770 from A-Akhil/fix/shader-sin-cos-series
fix(shader): take v_sin_f32 and v_cos_f32 from an exact series where the driver's result is more than 4 ulp off
2026-10-12 00:29:31 +02:00
Adrià e8169f49b3
Merge pull request #3756 from Lorkydey/feat/agc-acb-atomic-gds
feat(libSceAgc): build versioned ACB atomic GDS commands
2026-10-12 00:28:45 +02:00
eljackjoestar-cmd 9a0c59570c feat(ajm): decode Opus surround mapping family 2026-10-12 02:28:14 +04:00
Adrià f9e1d2541c
Merge pull request #3750 from fma-rc/feat/shader-subvector-loop
feat(shader): implement s_subvector_loop_begin and s_subvector_loop_end
2026-10-12 00:28:10 +02:00
Simon 233590462c fix(libSceNgs2): report EMPTY for a streaming sampler that played its queue
A playing sampler voice whose waveform still accepts blocks (CONTINUE)
reported only INUSE|PLAYING after it had played every queued block, so
a title that waits for EMPTY before it reuses the voice never did.
PPSA18391 (engine: Clickteam Fusion) reads state_flags & 0x22 != 2 from
sceNgs2VoiceGetState as the end of a sound; each of its sound effects
played once and never again.

The voice now also reports EMPTY (0x20) in that state and keeps
playing, so blocks added later still play. A waveform that was closed
without CONTINUE does not report it.
2026-10-12 00:26:12 +02:00
ethan 409f53eaed fix(relinker): filter non-reference RIP-relative FF operations 2026-10-11 15:24:53 -07:00
Adrià 5aaf26bd32
Merge pull request #3689 from MarcZX100/codex/libkernel-spin-reltimedwait-3554
feat(libkernel): implement pthread spinlocks and relative condition wait
2026-10-12 00:23:53 +02:00
Adrià d2fa71b706
Merge pull request #3682 from zmeizy/claude/kernel-fsync-error-codes
fix(libkernel): return SCE error codes from sceKernelFsync
2026-10-12 00:23:21 +02:00
Hussein Kadhim 351ca3bb12 fix(libkernel): return EDEADLK for a thread joining itself and EINVAL for a null thread
scePthreadJoin threw when a joinable thread joined itself and
scePthreadJoin and scePthreadDetach threw on a null thread, so
pthread_join and pthread_detach ended the process where FreeBSD libthr
returns EDEADLK and EINVAL.
2026-10-11 22:23:16 +00:00
Adrià c059590d8e
Merge pull request #3598 from Recapi/feat/libc-asinl
feat(libc): implement the remaining long double math functions RetroArch imports
2026-10-12 00:22:48 +02:00
Simon 43573fd48a fix(libSceVideoOut): return INVALID_HANDLE for events on ports that are not open
Registering a flip or vblank event on a handle that sceVideoOutOpen never
created, or that was closed, threw, which ended titles that register
their flip event before they open the port and ignore the result. The
documented error SCE_VIDEO_OUT_ERROR_INVALID_HANDLE is returned instead,
the same check sceVideoOutSetFlipRate and the other output calls use.

The flip test program gains an "unopened" mode.
2026-10-12 00:21:47 +02:00
Claude feb19a844d
fix(relinker): decode 3DNow! instructions with their ModRM and opcode suffix
0F 0F was decoded as a two-byte instruction. 3DNow! instructions are
0F 0F ModRM [SIB] [displacement] imm8, the trailing byte selecting the
operation (AMD64 Architecture Programmer's Manual Volume 3, Appendix A,
3DNow! opcodes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
2026-10-11 22:21:32 +00:00
Dean fabbeb393b
Merge pull request #3522 from pushkarreddyy/feat/libc-reallocf
feat(libc): implement reallocf
2026-10-12 11:21:30 +13:00
PrintOrb 665cca43a0
Merge branch 'main' into fix/videoout-high-frame-rate 2026-10-11 17:21:16 -05:00
Adrià 8fc53cb325
Merge pull request #3853 from billythemenace2/feat/rudp-ppsa06888-imports
feat(libSceRudp): declare the calls PPSA06888 imports
2026-10-12 00:20:03 +02:00
Dean Galvin 1dc342dd57 perf(agc): keep the highest index of a large in-place index buffer while it is unchanged
An indexed draw that binds its index buffer in place from a host import
(#2253) scans the bound range for its highest index on every draw, where
the copied path reuses the value kept with its snapshot. A draw of many
indices pays for the scan each time, and an indirect draw, which binds
the whole declared index buffer, scans the whole buffer per draw.

The recorder now keeps the highest index of an in-place index range of
4096 indices or more with the write generation collected before the
scan, and a draw takes it while the range is unchanged since
(GuestMemory::UnchangedSince and the allocation registry generation, as
for a reused snapshot). A smaller range is scanned at every draw as
before: the scan costs 0.4 ns per index and the write collect and lookup
0.2 to 1.4 us per draw, so the scan is the cheaper of the two below
about 3,000 indices, as #2253 measured on small ranges.
2026-10-12 11:19:50 +13:00
Adrià Franch 8c00fe871e docs(TechnicalDebt): put the InitParameter2 line where the old one was, not at the end of the file
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 22:19:14 +00:00
MarcZX100 d004d11fa3 fix(libSceJson2): use signed special-float enum type 2026-10-11 22:19:14 +00:00
David 1d5f5eb6c8 feat(libSceJson2): implement the InitParameter2 constructors and setSpecialFloatFormatType
Resident Evil 4 (PPSA07411, #2776) and PRAGMATA (PPSA02530, #3043) stop
on the absent export with

  what():  _ZN3sce4Json14InitParameter225setSpecialFloatFormatTypeENS0_22SpecialFloatFormatTypeE not implemented

Deathloop, Minecraft Legends and Cyberpunk import the base-object
constructor InitParameter2::InitParameter2(), InitParameterRtti2::
setAllocatorRtti and InitParameterRtti::InitParameterRtti(AllocParamRtti*,
void*, unsigned long), which were NotImplemented stubs.

InitParameter2 is the 40-byte object of SharpEmu and KytyPS5: the
allocator, its user data, the file buffer size and the 32-bit special
float format type at 0x18. Both constructors zero it, setAllocatorRtti
writes the allocation parameters and user data where setAllocator writes
the allocator, and setSpecialFloatFormatType stores the type.
InitParameterRtti's constructor writes its three arguments to the first
24 bytes. The NID WVZBP4IyM+E recomputes from the mangled name and is in
the aerolib database. The enum's values are unknown, so no value is
rejected; the inferred layouts are recorded in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 258f2910808e5ef1636973aaefbdf51615873dcb)
2026-10-11 22:19:14 +00:00
pushkarreddyy 931aaa2a7e feat(libkernel): handle sysctl queries for pathname, physmem and cacheline size 2026-10-12 00:17:14 +02:00
milescoviello 972caa4f2a fix(libkernel): number pthread keys from 1 as FreeBSD libthr does
scePthreadKeyCreate and pthread_key_create handed out the slot index,
so the first key in a process was 0. FreeBSD libthr returns slot + 1
(_pthread_key_create: "*key = i + 1") and subtracts 1 again in
pthread_key_delete, pthread_getspecific and pthread_setspecific, so 0 is
never a valid key. Code that keeps 0 as "key not created yet" therefore
created a new key on every call and lost the values it stored under the
previous one.

Keys now start at 1; 0 and other out-of-range keys are rejected with
EINVAL by delete and set and read as NULL, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYhZu5HokHMo9mfi8QU83m
2026-10-11 22:16:59 +00:00
jweidenh 2b8f151b3f test(agc): verify optimized pipeline draws and readback 2026-10-12 00:16:28 +02:00
Alex c63294027b fix(libc): exp2 leaves errno unchanged
exp2 set errno (34) for 1024.0. FreeBSD msun never sets errno and
reports errors through floating-point exceptions only, so errno is now
saved and restored around the host call.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 18:15:15 -04:00
Adrià 43bc17f7ed
Merge pull request #3727 from mariusyo07/fix/pad-vibration-mode-3
fix(pad): accept vibration mode 3
2026-10-12 00:14:30 +02:00
Adrià 24865e8e22
Merge pull request #3887 from AchrafReyani/fix/libc-windows-backtrace-stack-candidates
fix(libc): list stack return address candidates in Windows backtrace reports
2026-10-12 00:13:59 +02:00
Adrià 11d9c00cf6
Merge pull request #3884 from hansjm10/fix/sysmodule-agc-internal-id
fix(libSceSysmodule): recognize the libSceAgc internal module id
2026-10-12 00:13:05 +02:00
Adrià c8ad983fd4
Merge pull request #3871 from fdfawef324/fix/libc-log-line-one-write
fix(libc): write each log line in one call
2026-10-12 00:12:34 +02:00
Adrià f803854a5c
Merge pull request #3670 from SibteProf/fix/json2-initparameter2-base-constructor
fix(json2): implement InitParameter2 base constructor
2026-10-12 00:12:05 +02:00
Niko 5731e02841 fix(libkernel): close guest sockets in sceKernelClose
sceKernelClose passed every descriptor to the host close. Guest socket
descriptors start at 0x10000000 and are not host descriptors, so closing
an open socket returned SCE_KERNEL_ERROR_EBADF and left it in the guest
socket table with its host socket open. Route them to GuestSockets::Close
as close, sceKernelRead and sceKernelWrite already do; a closed socket
still returns SCE_KERNEL_ERROR_EBADF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 00:11:53 +02:00
Adrià af0b52ebb4
Merge pull request #3592 from MarcZX100/codex/socket-errno-errors-3573
fix(libkernel): map host socket errors to guest errno
2026-10-12 00:11:40 +02:00
Adrià b18d4feddd
Merge pull request #3580 from Amr-Youssef/feat/libkernel-sigwait
feat(libkernel): export pause, sigwait and sigwaitinfo
2026-10-12 00:11:14 +02:00
MrMha 3687b2e214 perf(relinker): use a flat sorted call-site index 2026-10-12 00:11:00 +02:00
Adrià 33067ca0c7
Merge pull request #3856 from ErenYeager1836/carry/recompiler-vector-window
perf(recompiler): keep relatively addressed vector registers in a window array
2026-10-12 00:10:58 +02:00
Adrià 59584d58b1
Merge pull request #3858 from LeandroLP23/fix/libc-internal-force-tls-destructor-windows-test
test(libSceLibcInternal): run guest_force_tls_destructor on Windows
2026-10-12 00:10:39 +02:00
Adrià 362a1f4e96
Merge pull request #3857 from gookie-dev/fix/libscexml-for-titles-that-list-it
fix(libSceXml): add an export-free libSceXml for titles that list it
2026-10-12 00:10:31 +02:00
Adrià 825cbd4106
Merge pull request #3531 from karanvora2599/perf/shader-native-packed-f16
perf(shader): compute v_pk_add_f16 and v_pk_mul_f16 with native f16 math
2026-10-12 00:10:02 +02:00
Adrià 10afe59c7d
Merge pull request #3851 from itsbo5/feat/libc-drand48-lrand48-mrand48-srand48
feat(libc): implement drand48, lrand48, mrand48 and srand48
2026-10-12 00:09:44 +02:00
Adrià 7667f53232
Merge pull request #3845 from semirkabir/feat/umtx-nwake-private
feat(libkernel): wake each listed address in _umtx_op UMTX_OP_NWAKE_PRIVATE
2026-10-12 00:09:31 +02:00
Adrià 93ba44d750
Merge pull request #3847 from semirkabir/feat/usbd-device-calls
feat(libSceUsbd): declare the device and handle calls for the no-device path
2026-10-12 00:09:29 +02:00
Adrià a93947040c
Merge pull request #3836 from nyavana/docs/libs-build-testing-refresh-20261011
docs(build): clarify when explicit libs target is required
2026-10-12 00:09:13 +02:00
Adrià 972b45b807
Merge pull request #3835 from queeeef/fix/agc-rect-list-partial-primitive
fix(agc): draw the complete rectangles of a rect-list draw with a partial last one
2026-10-12 00:09:05 +02:00
Adrià 7e4074fcb9
Merge pull request #3838 from gookie-dev/fix/pad-special-port-not-connected
fix(pad): report special ports as not connected in scePadOpen
2026-10-12 00:09:03 +02:00
Adrià c7731cf4d4
Merge pull request #3843 from kr4y4/fix/agc-aniso-override-force-degamma
fix(agc): keep FORCE_DEGAMMA paired when ANISO_OVERRIDE rebuilds a sampler
2026-10-12 00:09:01 +02:00
Adrià 31bf997b53
Merge pull request #3833 from David-cmrg/test/agc-gated-dispatch-short-spins
test(agc): split the gated dispatch producer spin into short dispatches
2026-10-12 00:08:18 +02:00
Kikoarl 7cf2ee844a test(libSceSysmodule): verify handle and symbol resolution for libSceAudioPropagation 2026-10-12 00:08:15 +02:00
Adrià 6407626dd1
Merge pull request #3830 from winstrex/fix/agc-flat-apertures-kernel-parts
test(agc): split agc_driver_flat_apertures by shader instead of by row
2026-10-12 00:08:14 +02:00
Aryan singh 7c1b64b0ca fix(relinker): share module suffixes between identity and import matching
The guest identity predicate accepted .debug_prx while Domain::ImportModule
did not: a dependency named libGuest.debug_prx normalised to
libGuest_debug_prx, so a qualified import declared in module libGuest was
left unscoped. When another guest module exported the same symbol, the
conversion failed with an ambiguous guest import, while .prx, .sprx and
.suprx resolved to the declaring module.

Module suffixes are now one list in the domain layer, used by the identity
predicate, import module normalisation and the default .prx suffix.
Needed-name stem aliasing keeps its own list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:38:07 +05:30
Aryan singh d3fc14a50c fix(relinker): resolve debug PRX dependencies by module identity 2026-10-12 03:38:07 +05:30
Adrià e53c30bcdf
Merge pull request #3828 from CouchRiv/fix-shader-combined-pknorm-f16
fix(shader): accept abs, neg and op_sel source modifiers on v_cvt_pknorm_i16_f16 and v_cvt_pknorm_u16_f16
2026-10-12 00:07:49 +02:00
Adrià 4b355d4e68
Merge pull request #3825 from kr4y4/fix/shader-dpp8-pk-fmac-f16
fix(shader): accept DPP8 on v_pk_fmac_f16
2026-10-12 00:07:47 +02:00
Adrià 01b7bb68be
Merge pull request #3823 from xXPBSXx/fix/rudp-exports-ppsa03490-v3
fix(rudp): provide the calls PPSA03490 still lacks
2026-10-12 00:07:39 +02:00
Adrià 1a7b96b5bc
Merge pull request #3822 from object05/test/f32-denormal-flush-split-fma
test(shader): accept the split fma sum in F32DenormalFlush
2026-10-12 00:06:56 +02:00
Adrià 5317eeb54e
Merge pull request #3817 from omurc4/feat/videoout-add-buffer-attribute-option
feat(libSceVideoOut): export sceVideoOutAddBufferAttributeOption
2026-10-12 00:06:21 +02:00
Adrià 2c8122c9f2
Merge pull request #3813 from jweidenh/codex/storage-upload-lifetime
fix(agc): retain storage textures during initial uploads
2026-10-12 00:05:54 +02:00
Adrià 12d684f4e6
Merge pull request #3807 from AchrafReyani/fix/shader-srt-signed-less-than-uniform
fix(shader): accept signed less-than in runtime SRT values
2026-10-12 00:05:43 +02:00
Adrià ed90d97346
Merge pull request #3810 from MiniRML/pr/videoout-test-driver
test(videoout): make SDL video driver configurable
2026-10-12 00:05:41 +02:00
Adrià 66e87807d5
Merge pull request #3804 from MarcZX100/codex/relinker-trap-sdk-syscalls-2136
feat(relinker): trap exact SDK syscall stubs on request
2026-10-12 00:05:38 +02:00
Adrià 4a8efe0699
Merge pull request #3808 from MarcZX100/codex/apr-command-size-validation-1930
fix(libkernel): validate APR command payload sizes
2026-10-12 00:05:34 +02:00
Adrià 5130c66b88
Merge pull request #3794 from semirkabir/feat/cpuset-getaffinity-process
feat(libkernel): report the process affinity from cpuset_getaffinity
2026-10-12 00:04:42 +02:00
hamb3r b8a1cbe42b fix(libc): add missing Unity engine static imports 2026-10-12 01:04:39 +03:00
Adrià e10f91b305
Merge pull request #3777 from MarcZX100/codex/agc-store-idle-3272
fix(agc): store pending storage-image results when queues idle
2026-10-12 00:04:39 +02:00
Adrià 0694c57998
Merge pull request #3693 from CouchRiv/fix-libc-asinf-errno
fix(libc): match FreeBSD asinf errno
2026-10-12 00:03:54 +02:00
Adrià acc5d29498
Merge pull request #3673 from MrMha/fix/stub-output-current
fix(stubgen): protect input files and keep stdout valid C++
2026-10-12 00:03:02 +02:00
Adrià dc70a66cbd
Merge pull request #3788 from xXPBSXx/fix/libkernel-mprotect-host-memory-v3
fix(libkernel): allow sceKernelMprotect on committed host memory outside the guest registry
2026-10-12 00:01:51 +02:00
Adrià 3929c21fb9
Merge pull request #3782 from MrMha/fix/rewrite-instruction-boundaries
fix(codegen): reject rewrites inside instructions
2026-10-12 00:01:46 +02:00
Adrià 949cd55471
Merge pull request #3785 from MrMha/fix/shader-cache-read-allocation
fix(shader): handle cache file allocation failures
2026-10-12 00:01:43 +02:00
Adrià 90933951d9
Merge pull request #419 from MichonGoddijn231849/feat/msaa-targets
feat(agc): multisampled color and depth targets with CB resolves
2026-10-12 00:01:37 +02:00
Mouhand Kaddo 82ac3bd93e fix(agc): skip read-only depth resummarize draws 2026-10-12 02:01:36 +04:00
Adrià 6566c9c8c6
Merge pull request #3784 from MrMha/fix/param-json-utf8
fix(libkernel): reject malformed UTF-8 in param JSON
2026-10-12 00:01:32 +02:00
David 6ce1240aba feat(libSceContentExport): implement the export session calls
sceContentExportStart hands out positive session ids, at most 10 live
(SharpProspero MaxExecution), and sceContentExportFinish closes them.
sceContentExportGetProgress, sceContentExportCancel and
sceContentExportFromDataWithThumbnail take their Orbital signatures and
check the session. The host has no media library to export into, so
FromDataWithThumbnail throws before it calls either data callback, and
GetProgress and Cancel throw for a live session since no export ever
runs and their result for an idle session is unknown. An eleventh Start
and Term with live sessions throw.

Titles: Cult of the Lamb PPSA06465 imports GetProgress, Cancel and
FromDataWithThumbnail (#2686); PPSA21564 (#271) and Cyberpunk 2077
PPSA04029 (#266) import Start.

Sources: Orbital tools/ida/db_types.json (cc408367) for the signatures,
SharpProspero Interop/Content/ContentExport.cs (5dfdb4b0) for the
session model and MaxExecution, shadPS4 content_export.h (443f0224) for
the parameter and callback layouts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 473d6dd355d2c0ee22f9792927e0e465846569cf)
2026-10-12 00:01:17 +02:00
Hannah Lyons c154b8bff3 feat(libkernel_sys): implement openat 2026-10-11 18:01:11 -04:00
Adrià 974116d38b
Merge pull request #3783 from jweidenh/codex/windows-partial-write-tracking
fix(libc): preserve writes during partial shared-memory collection
2026-10-12 00:01:08 +02:00
xXPBSXx 1b7e842b9c fix(exports): export the PS VR2 calls PPSA07411 imports that no library has
PPSA07411 (Resident Evil 4) fails to load without these imports. Their signatures are unknown, so they are declared without parameters and throw until they are implemented. Adds a TechnicalDebt entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:01:07 +02:00
David 5164f7875a feat(libSceVoiceQoS): implement sceVoiceQoSEnd
End clears the init flag set by sceVoiceQoSInit and returns 0, so the
library can be initialized again. Before an initialization it returns
0x804E0901 (LIBVOICEQOS_NOT_INIT), as measured on a PS5 (firmware 13.60)
in #1407.

LEGO Horizon Adventures (PPSA14632) calls it at shutdown and Ghost of
Yotei (PPSA26344) calls it on its sceVoiceQoSInit failure branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 25fbc944faddc5fb3519c4ce4b8d3600b3bc9e1b)
2026-10-12 00:01:03 +02:00
Adrià bb48d60fc6
Merge pull request #3774 from MrMha/fix/program-layout-ranges
fix(relinker): validate program layout ranges before writing
2026-10-12 00:00:46 +02:00
Adrià 7646a3f3ba
Merge pull request #3775 from eliyarson/docs/doom-linux-nvidia
docs: record DOOM homebrew on Linux with an NVIDIA GPU
2026-10-12 00:00:42 +02:00
Adrià 7ee8992714
Merge pull request #3776 from MrMha/fix/section-header-ranges
fix(relinker): validate complete allocated section ranges
2026-10-12 00:00:39 +02:00
Adrià 51e2c511e7
Merge pull request #3773 from xXPBSXx/fix/export-ppsa07411-imports-v4
fix(exports): export the calls PPSA07411 imports
2026-10-11 23:59:49 +02:00
Adrià 5acbcd64ba
Merge pull request #3768 from MarcZX100/codex/docs-dozen-workaround-3255
docs: document Windows Dozen driver workaround
2026-10-11 23:59:39 +02:00
Adrià f60fe21bc3
Merge pull request #3761 from semirkabir/feat/fiber-underscore-frame-pointer
feat(libSceFiber): add the underscore thread frame pointer export
2026-10-11 23:58:58 +02:00
Adrià 34ceeb05d0
Merge pull request #3760 from semirkabir/feat/ult-underscore-exports
feat(libSceUlt): add underscore mutex and queue create exports
2026-10-11 23:58:47 +02:00
Adrià d4938e1534
Merge pull request #3753 from jweidenh/codex/pthread-destructor-lifetime
fix(libkernel): run pthread key destructors before releasing thread state
2026-10-11 23:58:33 +02:00
Adrià c7b9719951
Merge pull request #3744 from ArekatlaNishanthchowdary/fix/pthread-rwlock-unlock-unowned
fix(libkernel): return EPERM when unlocking an rwlock that is not held
2026-10-11 23:57:59 +02:00
Adrià 9f0618548d
Merge pull request #3667 from MrMha/fix/convention-paths-current
fix(conventions): handle unusual Git paths and escaped links
2026-10-11 23:57:27 +02:00
Adrià b997cecfec
Merge pull request #3740 from jagrat04/feat/libSceAcm-fft-panner
feat(libSceAcm): implement sceAcm_FFT and sceAcm_Panner
2026-10-11 23:57:24 +02:00
Adrià df64fa9382
Merge pull request #3738 from Mouad-Scriptz-0/feat/agc-merged-vertex-tables
fix(agc): read a merged program's vertex tables past its hidden user words
2026-10-11 23:56:46 +02:00
Adrià 2b4b8178f9
Merge pull request #3603 from itsbo5/feat/libSceNpEntitlementAccess-offline-requests
feat(libSceNpEntitlementAccess): implement offline entitlement info r…
2026-10-11 23:56:38 +02:00
Adrià 72e67c0e50
Merge pull request #3555 from lisn0/feat/linux-named-shared-memory
feat(libkernel): support named shared memory on Linux
2026-10-11 23:55:30 +02:00
Adrià b6555c8454
Merge pull request #3714 from MarcZX100/codex/libkernel-aio-set-param-3708
feat(libkernel): implement sceKernelAioSetParam
2026-10-11 23:55:27 +02:00
Adrià c4d3b3a743
Merge pull request #3726 from NFSS10/perf/srt-plan-use-replacement
perf(shader): avoid copying SRT read uses
2026-10-11 23:55:24 +02:00
Adrià 32f6414314
Merge pull request #3713 from SleglJan/fix/libkernel-flexible-module-charge
fix(libkernel): count guest module segments against the flexible memory budget
2026-10-11 23:54:59 +02:00
Adrià 06664a44cd
Merge pull request #3717 from jweidenh/codex/nvidia-pipeline-replay
feat(agc): capture and replay compute pipeline compilation
2026-10-11 23:54:52 +02:00
Adrià 4a49ed06f7
Merge pull request #3712 from MarcZX100/codex/test-creat-errors-3303
test(libkernel): cover creat error cases
2026-10-11 23:54:51 +02:00
MarcZX100 8935160160 fix(libkernel): handle available sem_timedwait counts first
Co-authored-by: milescoviello <kitslayer29@gmail.com>
2026-10-11 23:54:18 +02:00
Adrià 1be2ca2028
Merge pull request #3706 from MarcZX100/codex/http-abort-wait-3156
feat(libSceHttp): implement abortable epoll waits
2026-10-11 23:53:59 +02:00
Adrià 0cff844842
Merge pull request #3707 from overlordxrz-source/feat/net-in6addr-linklocal-allnodes
feat(libSceNet): export sce_net_in6addr_linklocal_allnodes
2026-10-11 23:53:51 +02:00
David 774f21845d feat(libkernel): implement pthread_cond_reltimedwait_np
Add pthread_cond_reltimedwait_np (K953PF5u6Pc; computed with
tools/nid_names.py and matching aerolib.csv) as scePthreadCondTimedwait
with POSIX error numbers: ETIMEDOUT when the relative timeout expires,
EPERM when the caller does not hold the mutex, and the mutex held again on
return in every waiting case.

Titles: Porpoise PPSA99764 and RetroArch PPSA99169 import it.
Predicted from relink registry order, not observed: Porpoise stops with
"FAIL: unresolved ELF import K953PF5u6Pc from libkernel.prx" (registry
index 384; RetroArch index 490). No call site is resolved in the registry.

The third argument is a relative timeout in microseconds, not a
struct timespec. FreeBSD 11.4 libthr (8c639945a44588f6cfdddfb057bb5aad88735da0)
has no such function. shadPS4 (3a9f57265d28975658f1ca941daa5c879c7a74bd,
src/core/libraries/kernel/threads/condvar.cpp:229-234, 445, 467-468)
registers posix_pthread_cond_reltimedwait_np(cond, mutex, u64 usec) for this
NID and the same function for scePthreadCondTimedwait (BmMjYxmew1w), whose
microsecond argument this repository already implements. The width follows
the SCE twin's 32-bit SceKernelUseconds, as sem_reltimedwait_np does, not
shadPS4's u64. There is no timespec to validate, so no EINVAL case.
Recorded in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit c86ec8417d12f5b12136b0f06eae06493b0e7a62)
2026-10-11 23:53:37 +02:00
David 092f7ef00a feat(libkernel): implement the pthread spinlock calls
Add pthread_spin_init (ZMn3clnAGBA), pthread_spin_destroy (IJIggoPZExk),
pthread_spin_lock (pw+70ClLYlY), pthread_spin_trylock (rCTGkBIHfPY) and
pthread_spin_unlock (LEfMMCT+SlM). The NIDs were computed with
tools/nid_names.py and match aerolib.csv. libkernel has no scePthreadSpin*
twin in aerolib, so the calls are implemented directly, like the barrier.

Titles: Porpoise PPSA99764 and RetroArch PPSA99169 import pthread_spin_lock.
Predicted from relink registry order, not observed: after
pthread_cond_reltimedwait_np, Porpoise stops with
"FAIL: unresolved ELF import pw+70ClLYlY from libkernel.prx" (registry
index 387; RetroArch index 493). No call site is resolved in the registry.

Behaviour follows FreeBSD 11.4 libthr thr_pspinlock.c and thr_umtx.h
(8c639945a44588f6cfdddfb057bb5aad88735da0). The guest pthread_spinlock_t
holds a pointer to an allocated lock. EINVAL for a null or destroyed lock and
for a pshared other than PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED,
EBUSY from trylock while any thread holds the lock, EPERM from unlock by a
thread that does not hold it. libthr spins forever when the holder locks
again; that call throws here. A shared lock is allocated like a private one,
since guest code runs in one process. Recorded in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 13ebf7f926fa2ee1c825cb1fcf18451a8781c045)
2026-10-11 23:53:36 +02:00
Adrià 4989809b13
Merge pull request #3705 from MarcZX100/fix/asan-guest-arena-window-3634
feat(build): support Linux AddressSanitizer builds
2026-10-11 23:53:19 +02:00
Adrià c8536ab100
Merge pull request #3703 from utkuhalis/fix/macos-write-watch-fresh
fix(libc): track never-collected pages in the macOS write watch
2026-10-11 23:53:08 +02:00
Claude db49377bef fix(libkernel): return SCE error codes from sceKernelFsync
sceKernelFsync returned the host fsync or _commit result, so a failure
returned -1 instead of an SCE error code, and a guest socket descriptor
reached the host call. fsync then set the guest errno from the host
errno rather than from that result.

Handle sockets and return SCE error codes as sceKernelFdatasync does
(EINVAL for an open socket, EBADF for a closed one or an unknown
descriptor), and have fsync take the errno from sceKernelFsync's result
like the other POSIX wrappers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 23:53:00 +02:00
Adrià 9ce99f8f4d
Merge pull request #3697 from JAB-dev/fix/font-writing-letter-step
fix(libSceFont): return the letter step of sceFontWritingRefersRenderStepCharacter through a pointer
2026-10-11 23:52:50 +02:00
Adrià 4bde70b4e2
Merge pull request #3702 from oneandonlydean/up4/depth-tests-without-planes
fix(agc): leave the depth surface out when no enabled test has its plane
2026-10-11 23:52:46 +02:00
Adrià 6fa58ec0ac
Merge pull request #3696 from JAB-dev/feat/font-syllable-string-state
feat(libSceFont): implement sceFontCharacterGetSyllableStringState
2026-10-11 23:52:45 +02:00
David 059e1319d1 feat(libkernel): export pause, sigwait and sigwaitinfo
Exports pause (EDyhWelj7UY), sigwait (mrbHXqK8wkg) and sigwaitinfo
(Uq5BGthgbl4) from libkernel. NIDs computed with tools/nid_names.py and
matched in aerolib; ps5-payload-dev/sdk f5d40f02 sce_stubs/libkernel.c
places all three in libkernel.

They throw like the merged sigtimedwait (#3430), with the same message
pattern: "sigwait: waiting for a pending signal", "sigwaitinfo: waiting
for a pending signal" and "pause: waiting for a delivered signal". In
FreeBSD 11.4 (8c639945) sigwaitinfo is kern_sigtimedwait without a
timeout (sys/kern/kern_sig.c:1212), sigwait is the same wait returning
the error number (kern_sig.c:1150, lib/libthr/thread/thr_sig.c:676-728)
and pause is sigsuspend of the current mask (lib/libc/gen/pause.c:46-56).
AnyPS5 never leaves a guest signal pending (blocked signals are dropped
in Dispatch, raise delivers at once), so there is nothing to take, and
raise, kill and pthread_kill run a handler only on the calling thread,
so nothing can end a pause.

Titles (predicted stops, registry order; not observed runs):
- Ruffle PPSA68091, observed today
  "FAIL: unresolved ELF import 1t1-JoZ0sZQ from libSceLibcInternal.prx"
  (sinhf, #3519), predicted next
  "FAIL: unresolved ELF import EDyhWelj7UY from libkernel.prx"
  (pause, call site 0x8F7266).
- RetroArch PPSA99169: pause (0x30DB1, an address table entry).
- PS5MC PPSA99420: pause (0x3BD80F6, 0x3C9E220), sigwait (0x3C9E4C7),
  sigwaitinfo (0x3C9E588).
- XPSemu PPSA97358: sigwait (0xE02AEC, 0x1101294, 0x1101368), QEMU's
  dummy vCPU thread and sigwait_compat thread.

guest_sigtimedwait now also checks the three throws, with an empty set,
a null info, a SIGINT raised while blocked, and that neither the output
nor the blocked mask changes. TechnicalDebt records the call sites.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 23:52:33 +02:00
Adrià ca4ab0d5d6
Merge pull request #3687 from Lorkydey/fix/libc-atoi-guest-width
fix(libc): parse atoi through guest-width strtol
2026-10-11 23:51:52 +02:00
SibteProf eaa9ce97ca test(json2): isolate base constructor regression from float format changes 2026-10-11 23:51:46 +02:00
Codex 3d8db7b5a8 fix(json2): implement InitParameter2 base constructor
Carry the implementation and regression from lucfx18's PR #2823, retaining
the original Git author. Extend the regression with a leading guard and
typed default-field checks, and record the unverified console layout.

Source: https://github.com/boykopovar/AnyPS5/pull/2823
2026-10-11 23:51:34 +02:00
Adrià 153a0a58d6
Merge pull request #3588 from tv7/fix/apr-async-queue
fix(libkernel): run APR buffers past an unsatisfied wait on their own queue
2026-10-11 23:51:13 +02:00
Adrià 4658391b1f
Merge pull request #3681 from zmeizy/claude/kernel-file-errno-translation
fix(libkernel): translate host errno in the file functions' SCE errors
2026-10-11 23:51:05 +02:00
Adrià 53b928cb04
Merge pull request #3686 from zmeizy/claude/truncate-test-root
test(libkernel): skip the read-only truncate cases when running as root
2026-10-11 23:50:44 +02:00
Adrià 562149d750
Merge pull request #3685 from zmeizy/claude/kernel-sys-errno-translation
fix(libkernel_sys): translate host errors to guest errno numbers
2026-10-11 23:50:40 +02:00
Adrià dba34804ec
Merge pull request #3684 from zmeizy/claude/libc-prx-keep-needed
fix(build): keep libc.prx needed by every executable that links a prx
2026-10-11 23:50:32 +02:00
Adrià 05c2509c61
Merge pull request #3678 from Ondra97/codex/relinker-desktop-input-preservation
fix(relinker): preserve inputs when writing desktop assets
2026-10-11 23:49:58 +02:00
Adrià Franch 7663d8479c docs(technical-debt): note glibc errno for logb and remainder 2026-10-11 23:49:39 +02:00
Renan Pires a36b9092d1 feat(libc): implement the long double math functions RetroArch imports 2026-10-11 23:49:38 +02:00
Adrià 6c6c5552dc
Merge pull request #3677 from MarcZX100/carry/libkernel-delete-sharing-3316
fix(libkernel): allow delete sharing for open Windows files
2026-10-11 23:49:25 +02:00
Adrià 85e2b31b56
Merge pull request #3676 from MrMha/fix/ci-test-accounting-current
fix(ci): preserve test discovery and skip diagnostics
2026-10-11 23:49:23 +02:00
Adrià 8d57710c95
Merge pull request #3674 from MrMha/fix/release-packaging-current
fix(packaging): validate and stage release archives
2026-10-11 23:49:15 +02:00
Adrià 45682f090d
Merge pull request #3672 from MrMha/fix/nid-inventory-current
fix(nid-names): ignore comments and literals in symbol inventories
2026-10-11 23:48:44 +02:00
Adrià d956de8425
Merge pull request #3596 from Lorkydey/feat/libc-fstatvfs
feat(libc): implement guest fstatvfs volume statistics
2026-10-11 23:48:10 +02:00
Adrià 00b6457610
Merge pull request #3671 from MrMha/fix/dependency-declarations-current
fix(pr-overlap): bound explicit dependency declarations
2026-10-11 23:47:27 +02:00
Adrià cda695db72
Merge pull request #3666 from MrMha/fix/export-audit-current
fix(import-audit): validate ELF and PE exports before reporting
2026-10-11 23:46:56 +02:00
Adrià 2605ad6c76
Merge pull request #3669 from MarcZX100/carry/audioin-open-variants-3340
feat(libSceAudioIn): implement sceAudioInHqOpen and sceAudioInAsyncOpen
2026-10-11 23:46:54 +02:00
Adrià e05a603771
Merge pull request #3668 from CouchRiv/fix-shader-float-compare-clamp
fix(shader): accept the clamp bit on VOP3 float compares
2026-10-11 23:46:41 +02:00
Adrià 2b988061ed
Merge pull request #3665 from itsbo5/feat/libSceSigninDialog-completion
feat(libSceSigninDialog): complete offline sign-in dialog lifecycle
2026-10-11 23:45:50 +02:00
pushkarreddyy 324669722e feat(libkernel): implement pthread_attr_getstackaddr 2026-10-11 17:45:35 -04:00
pushkarreddyy 91bfd6a18c feat(libkernel): implement pthread_attr_getinheritsched, pthread_attr_getscope and pthread_attr_setscope 2026-10-11 17:45:17 -04:00
Adrià cbd98bbdc1
Merge pull request #3540 from ivica00/fix/srgb-bilinear-cube-zero
fix(shader): return 0 for an 8-bit sRGB bilinear cube comparison
2026-10-11 23:45:00 +02:00
Adrià f35bcafbee
Merge pull request #3662 from Celegans12/perf/recompiler-iteration-selection-storage
perf(recompiler): reuse sorted sets for iteration selection merges
2026-10-11 23:44:59 +02:00
Adrià f6203c150b
Merge pull request #3497 from LightStorm72/https-ca-list-stubs
fix(libSceHttp): return an empty CA list from sceHttpsGetCaList/sceHttpsFreeCaList
2026-10-11 23:44:40 +02:00
Adrià 097b8d82a5
Merge pull request #3621 from goncalompontes/feat/shader-vop3-interp-f32-e64
feat(shader): decode GFX10 VOP3-encoded interpolation
2026-10-11 23:44:35 +02:00
Adrià fe03a7d126
Merge pull request #3660 from Celegans12/fix/cache-replace-open-windows-files
fix(cache): replace entries while Windows readers retain old files
2026-10-11 23:44:25 +02:00
Adrià 34c94e1d42
Merge pull request #3639 from AchrafReyani/fix/libc-mspace-32-byte-alignment
fix(libc): align mspace allocations to 32 bytes
2026-10-11 23:44:18 +02:00
Adrià Franch e8ea9a62bb test(libkernel): check that a socket call returns the mapped guest errno
Sending on an unconnected UDP socket must report the guest EDESTADDRREQ (39)
through NativeError, so a regression to EIO is caught on Linux.
2026-10-11 23:43:47 +02:00
Hussein Kadhim d9c2622655 docs(libkernel): record the unreported nonblocking connect refusal and the recv after SHUT_RD difference
(cherry picked from commit c1519d951b2b77346392ccc18204f37c587e7eda)
2026-10-11 23:43:47 +02:00
Hussein Kadhim d694aac7b4 fix(libkernel): translate every host socket error to the guest errno of its name
NativeError listed 17 Winsock and 17 POSIX errors and turned every other
one into EIO. A second connect while the first is pending (WSAEALREADY,
EALREADY) and an option the host rejects (WSAENOPROTOOPT, ENOPROTOOPT)
reached the guest as EIO; on Linux a nonblocking connect (EINPROGRESS),
a send with no destination (EDESTADDRREQ), ENOTSOCK, EAFNOSUPPORT,
EOPNOTSUPP and others did too.

The translation moves to SocketError.hpp and covers the socket errors of
both hosts by name, with the FreeBSD 11 numbers. WSAESHUTDOWN stays EPIPE
as before. socketpair's own table is gone, as NativeError covers it.

(cherry picked from commit a889c98e6a59d62da289f2e6a77355d2b41a1bde)
2026-10-11 23:43:47 +02:00
Adrià e2ea125926
Merge pull request #3605 from CouchRiv/fix-libc-asin-nan-sign
fix(libc): asin(|x| > 1) returns the x86 default NaN and leaves errno unchanged
2026-10-11 23:43:44 +02:00
Adrià 57ba0e7bca
Merge pull request #3568 from DariusHQ/feat/libkernel-sendfile
feat(libkernel): implement sendfile
2026-10-11 23:43:14 +02:00
Adrià aab41deda0
Merge pull request #3541 from MarcZX100/codex/amd-ordered-nan-compare-3536
fix(shader): handle ordered NaN comparisons
2026-10-11 23:43:11 +02:00
Dean abd318d9c0
Merge pull request #3683 from Zurisen/fix/amm-below-host-regions
fix(libkernel): reserve the AMM ranges below host regions at the top of the guest arena
2026-10-12 10:43:07 +13:00
Dean b5e6b458e5
Merge pull request #3976 from pipe1os/fix/agc-host-imports-device-switch
fix(agc): keep another device's host imports until its teardown
2026-10-12 10:43:04 +13:00
jweidenh 2ac8c72383 test(agc): bound packed f16 SPIR-V scanner reads
FindF16x2Math read spirv[offset + 1] for every instruction once the f16 vector type was known, so a final one-word OpFunctionEnd read past the module. Check the opcode and its minimum word count before reading operands.
2026-10-11 23:43:03 +02:00
Karan Vora 660e24eeac perf(shader): compute v_pk_add_f16 and v_pk_mul_f16 with native f16 math
v_pk_add_f16 and v_pk_mul_f16 computed each half in f32 and rounded it
back to f16, then fixed the NaN, FP16_OVFL and clamp results on the
bits. On a device with native f16 that rounds to nearest even and keeps
f16 denormals (the Float16, RoundingModeRTE and DenormPreserve
capabilities that #1252 already checks), the arithmetic is now one
f16vec2 OpFAdd or OpFMul decorated NoContraction, and the same NaN,
FP16_OVFL and clamp rules run on its result bits.

The results don't change. f32 has at least 2 * 11 + 2 significand bits,
so rounding an f16 sum or product to f32 and then to f16 gives the
correctly rounded f16 result. Vulkan requires f16 OpFAdd and OpFMul to
be correctly rounded, the module keeps f16 denormals, and any NaN they
produce is replaced by the NaN the existing rules select.

v_pk_fma_f16 and v_pk_fmac_f16 keep the f32 path: Vulkan gives GLSL Fma
only the precision of OpFMul followed by OpFAdd, so a native f16 Fma
may round twice.

New test agc_driver_packed_float16_native compiles one shader with
packed add, mul, fma and fmac (op_sel, op_sel_hi, neg_lo, neg_hi and
clamp variants) with and without Float16, checks that only add and mul
use f16vec2 math, and compares every result bit for bit on random and
special inputs (zeros, denormals, infinities, NaNs, values near the f16
maximum) in nine float modes.
2026-10-11 23:43:03 +02:00
Celegans12 58ee73f475 fix(libc): write the whole what() when terminate reports an exception
The default terminate handler formatted its whole report into a 1024-byte
buffer, so a long what() was cut off without a trailing newline. Driver
refusals that carry a serialized RecompileRequest lost most of it, and the
next log line ran into the truncated text.

The report header still goes through the bounded RawLog, and what() is
now written in full by a raw write to the stderr handle, followed by a
newline. Both keep avoiding the CRT stream lock, as before.

exception_runtime gains a forked child that throws an uncaught
runtime_error with a message over 3000 characters and checks that the
full what() reaches stderr before SIGABRT.
2026-10-11 23:42:53 +02:00
Adrià Franch 208b908238 test(agc): register the multisampled target guest-access test in ctest
The test only ran in the full recorder binary, which no ctest entry starts. It now has its own mode and entry (agc_multisample_guest_access); with the guard back at the single-sample size its new padding row fails.
2026-10-11 23:41:30 +02:00
Adrià Franch 5c5912c49e fix(agc): guard a multisampled target's whole sample planes; docs for host-only multisampled targets
The guest-access guard covers CB bytes times samples (the single-sample layout size alone missed the later sample planes' tile padding), with a test row in that padding. Remove two TechnicalDebt lines duplicated by the rebase, document the guard bound and the unevicted targets, and add the multisampled targets to ARCHITECTURE.md.
2026-10-11 23:41:30 +02:00
Michon d109f3966f fix(agc): guest access to a multisampled color target's memory throws
A multisampled target's samples are only on the host, so its guest memory
never holds them: a CPU read through GuestMemory::Read/ReadCommitted, a
DMA_DATA copy from it and a texture or storage image lookup at its address
throw instead of returning bytes that were never written there. Asked by
oneandonlydean; the test reads a resolved-only target's memory each way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Michon b64da7caf7 fix(agc): GPL fragment libraries keyed by the sample count
The fragment shader and fragment output libraries are built with the
pipeline's rasterizationSamples, so a 1x and a 4x pipeline with the same
shaders and formats must not share them. Reported by adriadam10 (found by
Raghav314 in #2242).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Michon ae6dfd9073 fix(agc): the standard 8x pattern's last sample is at (7, -7)
Vulkan's standard 8x sample 7 is (0.9375, 0.0625), (7, -7) in signed sixteenths; the table had (7, -8), so the
standard pattern (PPSA99902's PA_SC_AA_SAMPLE_LOCS words 0xbd153fd1 / 0x9773f95b) was refused as nonstandard.
Regression row with those words.

Reported by @Amoenus.

Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Michon eeefb06549 fix(agc): multisampled targets use main's CMASK fields; their CMASK state refuses what it cannot model
The duplicate ColorTarget::cmaskAddress, decode and size helper are gone: multisampled targets
use main's cmaskAddress/cmaskBytes (whole metablocks). Single-sample targets keep main's rule
(CMASK under FAST_CLEAR); a multisampled one takes it under FAST_CLEAR or COMPRESSION. A zero
fill of the whole CMASK clears at the next use, 0xFFFFFFFF marks it expanded, any other or
partial fill refuses the next use; eliminate/DCC passes over a multisampled target and a CB
resolve into a fast-clear destination are refused. The draw key adds CMASK_BASE_EXT (0x398),
which main decodes but did not key.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Michon 163947ef72 style(agc): drop code comments the conventions check rejects
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Michon ebf361103c feat(agc): multisampled color and depth targets with CB resolves
Draws with PA_SC_AA_CONFIG multisampling (2, 4 or 8 samples, every target with as many
fragments, the standard sample locations, MSAA_ENABLE) render into host-only multisampled
color images and multisampled depth surfaces; the pipeline rasterizes with that sample
count. A CB_COLOR_CONTROL resolve over a multisampled CB0 runs as a render pass whose
resolve attachment is CB1's resident image. A zero fill over a target's CMASK fast-clears
it to the CB_COLOR_CLEAR_WORD values of its next use. EQAA, coverage conversion,
nonstandard sample locations, sampling a multisampled surface and multisampled mips stay
refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 23:41:30 +02:00
Adrià 50d3f0691f
Merge pull request #3529 from oguzhanozfe/codex/windows-identical-function-export-aliases
fix(relinker): allow identical Windows function export aliases
2026-10-11 23:41:27 +02:00
ThatsLeo 58d59f6279 fix(shader): fold a lane's s_wqm bit of the starting pixel lanes to true
Vulkan starts only quads holding a non-helper lane, so the bit is set in every
lane it runs. Stray's pixel shader 0x2012f90000 keeps the packed ancillary
word where that bit is clear, and failed with an unsupported live use.

(cherry picked from commit 2068089b3d75fae55d0994a0916a22bffd7ee2a4)
2026-10-11 21:41:01 +00:00
Adrià 752db7da76
Merge pull request #3569 from DariusHQ/fix/libc-format-positional-arguments
fix(libc): format positional arguments on Windows
2026-10-11 23:40:52 +02:00
Adrià Franch 9ac63c0af8 style: restore blank lines touched by accident 2026-10-11 23:40:51 +02:00
bilel 11f329fd4b fix(libkernel): reject identity changes before ordinary-file fallback
A descriptor replaced before the shared-memory path probe can otherwise
bypass the pinned-object identity check through native fallback. Compare
the negative probe's current file identity to the initial snapshot and
reject a mismatch. Exercise the earlier window with an ordinary file for
all six descriptor operations.

Confidence: high
Scope-risk: narrow
Tested: 18 Linux runtime tests with zero skips; 18 deterministic reuse scenarios; affected three patched modules; standalone ASan/UBSan; Clang analyzer; conventions and diff checks
Not-tested: Full project build/suite, Windows runtime, console hardware and titles
Directive: Identity checks do not synchronize the entire descriptor table or identify separate opens of the same inode
2026-10-11 23:40:46 +02:00
bilel f6ef5a77e2 fix(libkernel): preserve patched loading and shared-memory object identity
Keep guest creation-mask state in libc behind C-linkage helpers so NID
patching preserves the shared exports. Reject a pinned descriptor whose
file identity differs from the snapshot taken before classification.
Exercise close and reuse from another thread at both acquisition windows
for writes, resize and seek, and create temporary ordinary-file fixtures
so runtime tests work without the source tree.

Constraint: NID exemptions require the literal suffix at the end of the exported symbol
Confidence: high
Scope-risk: narrow
Tested: 18 targeted Linux runtime tests with zero skips; patched_libraries for libc/libkernel/libkernel_sys; standalone ASan/UBSan with warnings as errors; source-prefix-remapped fixtures; Clang analyzer and conventions
Not-tested: Full project build and library set, Windows runtime, console hardware and titles
Directive: Device/inode validation establishes file identity, not open-file-description identity
2026-10-11 23:40:46 +02:00
bilel 72b3a2abdd fix(libkernel): keep shared-memory identity and guest permissions consistent
Pin the descriptor before mmap validation so guest descriptor reuse cannot
redirect the eventual mapping. Apply the canonical guest creation mask when
creating named objects, distinguishing new objects before setting permissions
without changing the host process umask. Add regressions that reproduce both
failures and document the remaining host requirements.

Constraint: Guest umask must not mutate the process-wide host mask
Confidence: high
Scope-risk: narrow
Tested: 17 targeted Linux runtime tests passed with zero skips; conventions and diff checks; Clang analyzer on three changed production translation units
Not-tested: Full project build and suite, Windows runtime, console hardware and titles
2026-10-11 23:40:46 +02:00
bilel 2aaeaa3f05 feat(libkernel): make Linux shared memory usable through guest APIs (#3923)
Complete the object lifecycle through guest mapping and unlink APIs, and
preserve FreeBSD shared-object size and seek rules across scalar, vector
and asynchronous descriptor writes. Pin descriptors during operations and
coordinate size-sensitive operations across cooperating emulator processes.

Constraint: Linux host support with existing dependencies and allocation tracking
Rejected: Bare descriptor registry | close, duplication and reuse invalidate identity
Rejected: Per-object OFD locks | forked descriptors share the same lock description
Confidence: high
Scope-risk: moderate
Directive: Keep guest resize, truncating open and bounded writes under the same namespace guard
Tested: Ten Linux runtime suites; focused shared-memory ASan/UBSan suite with warnings as errors
Not-tested: Windows build, PS5 hardware and title compatibility
2026-10-11 23:40:45 +02:00
bilel zenned f274ceb18d feat(libkernel): allow Linux guests to reopen named shared memory (#3921)
Translate guest named-open flags and permissions to POSIX shared-memory descriptors. Bound guest names and use the existing digest implementation to keep a stable AnyPS5 namespace, including long names and internal slashes. Preserve anonymous and Windows behavior, and record the separate unlink and guest mapping gaps.

Constraint: Builds and tests run only through the enrolled 191 compute service.
Rejected: Direct Linux guest names | cannot represent FreeBSD internal slashes and 1023-byte names.
Tested: Source review and diff checks; baseline job100619 accepted, result retrieval currently times out.
Not-tested: Runtime verification pending on191; full build, Windows and titles.
Confidence: medium
Scope-risk: narrow
2026-10-11 23:40:45 +02:00
bilel zenned eeb647c6b5 test(libkernel): expose the missing named shared-memory path (#3921)
Exercise named object creation, reopening, descriptor permissions, truncation and cross-process identity before adding Linux support. The standalone target compiles the production implementation without graphics dependencies.

Tested: Source and staged diff reviewed; failing baseline will run on 191.
Not-tested: Full runtime build and Windows.
2026-10-11 23:40:45 +02:00
Adrià 951fd9afcb
Merge pull request #3590 from karanvora2599/perf/shader-f16-minmax-bits
perf(shader): pick f16 min, max and med3 results on the bits
2026-10-11 23:39:47 +02:00
Adrià 8a13a1b8ef
Merge pull request #3594 from Scramblrrrr/codex/windows-host-write-watch-exclusion
fix(agc): exclude host arena holes from write-watch proofs
2026-10-11 23:39:34 +02:00
Adrià 07eacac68c
Merge pull request #3591 from QRMOE/fix-libkernel-clock-getres-null
fix(libkernel): honor null clock_getres output
2026-10-11 23:39:27 +02:00
Adrià da07b30b26
Merge pull request #3589 from MrMha/fix/relinker-elf-reader-validation
fix(relinker): validate ELF section tables and file mappings
2026-10-11 23:39:02 +02:00
Adrià 372fb03284
Merge pull request #3586 from jradelmo/feat/http-uri-authority-delimiter
fix(libSceHttp): retain authority delimiter for partial URI builds
2026-10-11 23:38:55 +02:00
Adrià 87d7ab7950
Merge pull request #3551 from ducloc080202/fix/libc-unhandled-throw-site
fix(libc): name the throw site in unhandled exception reports
2026-10-11 23:38:35 +02:00
Adrià 7c8df1f0e4
Merge pull request #3583 from DariusHQ/feat/libc-wcstok
feat(libc): implement wcstok
2026-10-11 23:38:25 +02:00
Adrià c60f65a227
Merge pull request #3535 from sktharunbalaji13-cmd/contrib/libSceHttp2-invalid-id
fix(libSceHttp2): validate SSL setter handles
2026-10-11 23:37:50 +02:00
Adrià f5824092cf
Merge pull request #3545 from babyhuey/feat/posixforwebkit-fnmatch
feat(libScePosixForWebKit): implement fnmatch
2026-10-11 23:37:41 +02:00
Adrià 011c26cd5e
Merge pull request #3578 from LeandroLP23/fix/libkernel-fsync-read-only-windows
fix(libkernel): sync read-only and directory descriptors on Windows
2026-10-11 23:37:24 +02:00
Adrià 1342c4b9df
Merge pull request #3539 from MarcZX100/codex/agc-write-data-dst3-3534
fix(agc): accept WRITE_DATA destination 3 for memory fences
2026-10-11 23:36:57 +02:00
Adrià 0b7b479a04
Merge pull request #3576 from parl0v/refactor/agc-dcb-atomic-gds-0900
refactor(agc): name zARR5aCmkoY sceAgcDcbAtomicGds_0900
2026-10-11 23:36:55 +02:00
Adrià 24ba6b1764
Merge pull request #3577 from parl0v/refactor/audioin-pad-embedded-mic
refactor(audioin): name X+4jdIS75P0 sceAudioInIsPadEmbeddedMic
2026-10-11 23:36:48 +02:00
Adrià a672688e94
Merge pull request #3523 from XairRrR/fix/agc-default-unexported-pixel-inputs
fix(agc): read zero for pixel inputs of parameters the vertex stage does not export
2026-10-11 23:36:20 +02:00
Adrià 7de666a937
Merge pull request #3512 from LeandroLP23/fix/shader-mix-f16-directed-rounding
fix(shader): round v_fma_mixlo_f16 and v_fma_mixhi_f16 in every f16 rounding mode
2026-10-11 23:36:15 +02:00
Adrià 4d55bf10be
Merge pull request #3493 from AchrafReyani/feat/libkernel-ioctl
feat(libkernel): export _ioctl and getsid
2026-10-11 23:35:53 +02:00
Adrià 195f55eb97
Merge pull request #3572 from Lorkydey/feat/libkernel-getitimer
feat(libkernel): query real-time alarms with getitimer
2026-10-11 23:35:45 +02:00
Adrià b6b7deb0f4
Merge pull request #3574 from marshmll/fix/linux-sdl-audio-backends
fix(build): require an SDL audio backend on Linux
2026-10-11 23:35:42 +02:00
Adrià 41f013f664
Merge pull request #3567 from DariusHQ/fix/libc-format-grouping-flag
fix(libc): accept the ' flag in Windows formatting
2026-10-11 23:34:57 +02:00
Adrià ac1c340392
Merge pull request #3571 from EdouardSence/feat/json-parser-stream-parse
feat(libSceJson2): add sce::Json::Parser::parse with a read callback
2026-10-11 23:34:48 +02:00
Adrià dafc085adb
Merge pull request #3566 from DariusHQ/fix/libc-format-alternate-octal-zero
fix(libc): print 0 for %#.0o of zero on Windows
2026-10-11 23:34:44 +02:00
Adrià 7450e4dae6
Merge pull request #3570 from EdouardSence/feat/json-array-copy-clear-front-stream-parse
feat(libSceJson2): add the sce::Json::Array copy constructor, clear, front and iterator::operator->
2026-10-11 23:34:22 +02:00
Adrià ada499b635
Merge pull request #3561 from XairRrR/fix/agc-swap-alt-review-guards
fix(agc): reject constant color factors and memory-writing stages in split SWAP_ALT blends
2026-10-11 23:34:15 +02:00
Adrià 4085df4667
Merge pull request #3565 from ivica00/feat/libc-powisf2
feat(libc): implement __powisf2
2026-10-11 23:34:08 +02:00
Adrià 3ccef6abcd
Merge pull request #3564 from Aathish-D/feat/libc-ftrylockfile
feat(libc): implement ftrylockfile
2026-10-11 23:34:00 +02:00
Mouhand Kaddo 121b16fb4b fix(libkernel): guard Unix host polling in Windows select 2026-10-12 01:33:53 +04:00
Adrià c892804260
Merge pull request #3560 from EdouardSence/feat/razorcpu-push-marker
feat(libSceRazorCpu): add sceRazorCpuPushMarker
2026-10-11 23:33:24 +02:00
Adrià e44b7cf78c
Merge pull request #3546 from AlxcBTW/fix/vertex-narrow-wave-entry-2
fix(recompiler): give wave64 vertex programs on 32-lane hosts a 32-lane s3
2026-10-11 23:33:16 +02:00
Adrià 9d5c6afcd6
Merge pull request #3559 from EdouardSence/feat/ngs2-report-handler-exports
feat(libSceNgs2): export sceNgs2ReportRegisterHandler and sceNgs2ReportUnregisterHandler
2026-10-11 23:33:12 +02:00
Adrià 62f8758711
Merge pull request #3544 from babyhuey/feat/libkernel-execv
feat(libkernel): export execv
2026-10-11 23:33:07 +02:00
Adrià c56ea3b343
Merge pull request #3537 from hugodearaujo/feat/ppsa15878-vr2-exports
feat(libs): declare the PS VR2 exports PPSA15878 imports
2026-10-11 23:32:40 +02:00
Adrià 2ebe73da53
Merge pull request #3543 from Lorkydey/fix/relinker-none-relocations
fix(relinker): ignore no-op executable relocations
2026-10-11 23:32:26 +02:00
Adrià ceab34ad63
Merge pull request #3538 from hugodearaujo/fix/sysmodule-id-zero
fix(libSceSysmodule): return INVALID_VALUE for module id 0
2026-10-11 23:32:24 +02:00
Adrià b2477d9804
Merge pull request #3530 from MarcZX100/codex/libkernel-inet-text-rules-3126
fix(libkernel): follow FreeBSD inet text rules
2026-10-11 23:32:18 +02:00
Adrià 28400c02d1
Merge pull request #3542 from BharatYadav007/bharat/libc-setlogmask
feat(libc): implement setlogmask
2026-10-11 23:32:17 +02:00
milescoviello 9421484572 fix(libkernel): fail open with O_NOFOLLOW on a symbolic link
sceKernelOpen built the host flags from the bits it knows and dropped
O_NOFOLLOW (0x100), so open and sceKernelOpen with O_NOFOLLOW followed
a symbolic link and opened its target, and with O_CREAT created the
missing target of a dangling link.

FreeBSD looks up the last component without following it when
O_NOFOLLOW is set (sys/kern/vfs_vnops.c, vn_open_cred:
"((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF", and with
O_CREAT "if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
ndp->ni_cnd.cn_flags |= FOLLOW;"), and then refuses the link itself in
vn_open_vnode: "if (vp->v_type == VLNK) return (EMLINK);".

open now fails with EMLINK when O_NOFOLLOW is set and the path names a
symbolic link. O_CREAT | O_EXCL keeps failing with EEXIST, and a
trailing slash still resolves through the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:30:23 +00:00
milescoviello e8cb97e6e2 fix(libkernel): fail rmdir on a symbolic link instead of removing it
sceKernelRmdir, and rmdir through it, checked the path with
std::filesystem::is_directory and is_empty, which follow a symbolic
link, and then removed the path itself. So rmdir on a link to an empty
directory returned 0 and deleted the link, while the target stayed.

FreeBSD looks up the last component of rmdir's path without following
it (sys/kern/vfs_syscalls.c, kern_rmdirat: NDINIT_ATRIGHTS with
LOCKPARENT | LOCKLEAF and no FOLLOW) and then fails with ENOTDIR for
anything that is not a directory: "if (vp->v_type != VDIR) { error =
ENOTDIR; goto out; }". A link, whether it points to a directory or
nowhere, is a VLNK there.

rmdir now returns ENOTDIR for a symbolic link and leaves it alone, as
unlink already looks at the link itself through symlink_status. A
trailing slash still resolves through the link, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:30:23 +00:00
milescoviello 3ba4532352 fix(libkernel): reset a once control when its initializer exits or is cancelled
pthread_once and scePthreadOnce marked the control as running, called
the initializer and marked the control done only after it returned. A
thread that left the initializer through pthread_exit or a
cancellation point never came back, so the control stayed in progress
and every later call on it waited forever.

FreeBSD libthr runs the initializer under a cleanup handler
(lib/libthr/thread/thr_once.c, _pthread_once:
"THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
init_routine(); THR_CLEANUP_POP(curthread, 0);"). once_cancel_handler
stores ONCE_NEVER_DONE and wakes the waiters, and thread exit and
cancellation run the cleanup handlers. POSIX requires this for
cancellation: "if init_routine is a cancellation point and is canceled,
the effect on once_control shall be as if pthread_once() was never
called."

Both functions now push such a handler around the initializer, so the
control returns to its initial state and the next caller, or one
already waiting, runs the initializer. scePthreadOnce waiters now retry
when the control goes back to its initial state, and an exception from
its initializer resets the control as it already did for pthread_once.
CleanupHandler moves to Cancel.hpp so that Once.cpp can use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:30:23 +00:00
Adrià 9bee015035
Merge pull request #3524 from XairRrR/perf/agc-attach-2d-array-layers
fix(agc): render a slice of a 2D array color target into that layer of the array
2026-10-11 23:30:07 +02:00
Adrià 039d21ead8
Merge pull request #3527 from Sanjaysrinivas/fix/agc-buffer-memory-recovery
fix(agc): reclaim idle buffers on allocation OOM
2026-10-11 23:30:03 +02:00
ivica00 cd814b8c6f fix(shader): return 0 for an 8-bit sRGB bilinear cube comparison
An 8-bit sRGB compare is already 0 for every texel, so the selected face cannot change the result.
2026-10-11 23:29:39 +02:00
Adrià 989146c3b9
Merge pull request #3514 from gookie-dev/perf/kernel-module-info-frame-tables
perf(libkernel): read a loaded image's unwind tables once in sceKernelGetModuleInfoFromAddr
2026-10-11 23:29:38 +02:00
Adrià b0fd7c017e
Merge pull request #3517 from ee6aba54/fix/trophy2-null-outputs
fix(libSceNpTrophy2): accept a null details or data in GetTrophyInfo and GetGroupInfo
2026-10-11 23:29:33 +02:00
Adrià d2e1f20edb
Merge pull request #3499 from blawesom/carry/ampr-cnd-signal
feat(libSceAmpr): implement _Cnd_signal and _Cnd_init_with_name
2026-10-11 23:29:11 +02:00
Adrià d1f198d468
Merge pull request #3509 from Lorkydey/fix/relinker-module-dir-boundaries
fix(relinker): normalize additional module directory paths
2026-10-11 23:29:09 +02:00
Adrià 59559c306c
Merge pull request #3496 from MarcZX100/codex/primstate-normalize-disabled-vgpr-3457
fix(agc): preserve hand-built user VGPR offsets
2026-10-11 23:29:06 +02:00
Adrià a9a34e91cc
Merge pull request #3412 from pushkarreddyy/feat/agc-draw-snapshot-cap
perf(libSceAgcDriver): cap draw input snapshot allocation size
2026-10-11 23:28:42 +02:00
Ahir Barman Maji 52c7470b15 fix(shader): find the shader cache directory on macOS
ShaderCacheDirectory located the executable through /proc/self/exe,
which macOS does not have, so it returned an empty path there and
the shader and pipeline disk caches were silently disabled unless
ANYPS5_SHADER_CACHE_DIR was set. Use _NSGetExecutablePath and
resolve the path with std::filesystem::canonical on macOS. Linux
and Windows are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:56:34 +05:30
Mouhand Kaddo 9d8ee3de7d fix(shader): isolate single-block loop continue targets
Route semantic self-loops through a dedicated empty back-edge block. This prevents block merging from folding the continue target into the loop header when memory instructions emit nested selections. Add a synthetic loop-store regression that fails SPIR-V validation after optimization on main.
2026-10-12 01:26:17 +04:00
Adrià 14a7e64dcd
Merge pull request #3485 from santhoshkumar-dev/codex/windows-path-traversal
fix(filesystem): reject invalid parent traversal on Windows
2026-10-11 23:24:37 +02:00
Adrià 7562b4b05e
Merge pull request #3473 from superhe11/fix/resource-cache-storage-eviction
fix(agc): keep uncached storage images out of the resource cache
2026-10-11 23:24:32 +02:00
Adrià 90896b5cc9
Merge pull request #3462 from exefer/fix/libkernel-select-host-descriptors
fix(libkernel): select descriptors that are not sockets
2026-10-11 23:24:27 +02:00
Adrià 1770f352d7
Merge pull request #2471 from Scramblrrrr/codex/shared-loop-exit
fix(shader): guard shared loop exit routing and preserve valid fallbacks
2026-10-11 23:24:02 +02:00
Adrià 4cacc78d61
Merge pull request #3391 from tibzejoker/fix/masked-select-wqm-superset
fix(shader): drop masked selects proven unobserved through whole quad mode
2026-10-11 23:23:58 +02:00
Adrià 9865c57f76
Merge pull request #2261 from Sanjaysrinivas/feat/registered-ngg-workgroup
fix(agc): route registered NGG workgroups through mesh
2026-10-11 23:23:54 +02:00
Adrià fc5faefc44
Merge pull request #3159 from XairRrR/perf/agc-shader-prep-lock
perf(agc-driver): prepare shader ABI variants before taking the preparation lock
2026-10-11 23:23:53 +02:00
Adrià 515464844d
Merge pull request #1250 from kr4y4/fix/shader-fract-sub-floor
fix(shader): compute V_FRACT_F32 from the exact fraction of |x|
2026-10-11 23:23:29 +02:00
Adrià c5da8233a5
Merge pull request #3515 from Winvoker/fix/progress-stub-call-whitespace
fix(progress): match stub calls across whitespace
2026-10-11 23:16:46 +02:00
Adrià 9c75aa87c3
Merge pull request #3513 from jweidenh/codex/test-bda-store-boundaries
test(recompiler): cover BDA store boundary faults and written pages
2026-10-11 23:15:57 +02:00
Adrià Franch 7ca6b63905 docs(technical-debt): note the CA list stubs skip context validation
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 23:15:05 +02:00
LightStorm72 1d5f699439 fix(libSceHttp): return an empty CA list from sceHttpsGetCaList/sceHttpsFreeCaList 2026-10-11 23:15:05 +02:00
Ahir Barman Maji f30f3e8a84 fix(libs): find the executable directory on macOS
libSceFont and libSceNpEntitlementAccess located the executable
through /proc/self/exe, which macOS does not have, so finding the
system fonts and the entitlements file threw there. Use
_NSGetExecutablePath and resolve the path with
std::filesystem::canonical on macOS. Linux and Windows are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:38:05 +05:30
Claude 11fa3ab843
fix(libc): keep getenv results valid when other variables change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 21:07:20 +00:00
Claude 1489400189
fix(libc): set EINVAL when getenv gets an invalid name
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 21:06:35 +00:00
Adrià Franch 76d43c525e fix(libkernel): drop _ioctl, already exported by #3487
Co-authored-by: Achraf Reyani <noreply@users.noreply.github.com>
2026-10-11 23:06:10 +02:00
Achraf Reyani 6c7a2cbe69 feat(libkernel): export _ioctl and getsid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:06:10 +02:00
Adrià b3ae112012
Merge pull request #3528 from MarcZX100/codex/agc-shutdown-3506
fix(agc): catch shutdown in shader ABI resolution
2026-10-11 23:06:08 +02:00
Claude fe4a2cf7d8
fix(libc): run atexit handlers in one order with __cxa_atexit destructors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 21:05:51 +00:00
Adrià 9d9f2cf094
Merge pull request #3516 from Feuris/carry/windows-udp-short-receive
fix(net): preserve truncated UDP receives on Windows
2026-10-11 23:05:37 +02:00
Adrià 68ac73f3df
Merge pull request #3452 from LeandroLP23/fix/kernel-windows-directory-rewind
fix(libkernel): rewind Windows directory descriptors on lseek
2026-10-11 23:05:29 +02:00
Adrià d80a52b75d
Merge pull request #3500 from notaxeltv/feat/tts2-unavailable-exports
feat(libSceTextToSpeech2): return EOPNOTSUPP from remaining speech exports
2026-10-11 23:04:31 +02:00
Claude e463c5d11f
fix(libkernel): clamp POSIX deadlines beyond the clock range instead of overflowing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 21:01:57 +00:00
Claude 74d44b8e6c
fix(libkernel): try the lock before checking the pthread_mutex_timedlock deadline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 21:00:30 +00:00
Claude 29af23e718
fix(libkernel): apply the memory type in sceKernelMemoryPoolBatch type-protect entries
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 20:58:50 +00:00
Claude 602a76fc26
fix(libkernel): let pthread_barrier_destroy wait for released waiters
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 20:57:22 +00:00
dantdmdarealguy 3c581619d3 feat(input): configure stick deadzones and mouse sensitivity
anyps5-input.ini accepts LeftStickDeadzone and RightStickDeadzone (whole
percent, 0 to 90), a radial deadzone on the controller sticks whose
remaining travel is rescaled to the full range, and MouseSensitivity
(above 0, at most 10), which replaces the fixed factor of 1 for mouse
look. The defaults keep the current mapping exactly.
2026-10-11 15:57:12 -05:00
Adrià Franch 8e5091c2f0 docs(technical-debt): name the SPIR-V rule behind keeping the loop back edge
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 22:57:06 +02:00
XairRrR 0ad1a46884 test(agc): reject a split SWAP_ALT draw whose vertex shader stores to memory
The 8_8 SWAP_ALT blend test now also draws with a vertex shader that
stores a dword to a buffer (buffer_store_dword through user data 4-7)
and a separate alpha blend, and requires the draw to be rejected for
its shaders writing memory. With the former pixel-only check the draw
went through and the test fails.
2026-10-11 22:44:57 +02:00
Felipe Arce 4966917282 fix(agc): park retired host imports through shared_ptr so Imports() stays in place 2026-10-11 17:38:22 -03:00
jweidenh 3740c233bc fix(agc): accept core Vulkan capabilities during compute replay 2026-10-11 16:34:26 -04:00
Kikoarl 5d298b6d95 feat(libSceSysmodule): register libSceAudioPropagation module ID (0x120) 2026-10-11 22:33:22 +02:00
Felipe Arce 25f5afe645 fix(agc): keep another device's host imports until its teardown 2026-10-11 17:25:29 -03:00
jweidenh 598e991bca test(agc): provide the binding flag fixture placeholder buffer 2026-10-11 16:20:28 -04:00
Jordan Hans 2d3dd337ad fix(libSceNet): accept guest socket addresses whatever their sa_len 2026-10-11 20:17:41 +00:00
Alberto Ruiz e31b757c1e fix(libkernel): limit param.json nesting depth
parseJsonValue recursed without a limit, so a param.json with tens of
thousands of nested arrays overflowed the stack. Reject nesting beyond 512
levels, the limit libSceJson2 uses.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5WJS4ZdQynAJesCZKH5hb
2026-10-11 22:15:15 +02:00
jweidenh a4ae6d7e31 fix(agc): capture larger compute modules and binding flags 2026-10-11 16:14:44 -04:00
jweidenh decbac9bb4 fix(agc): link capture tests with the Windows exception runtime 2026-10-11 16:09:48 -04:00
jweidenh 8fbd0eecc1 feat(agc): capture and replay compute pipeline compilation 2026-10-11 16:09:48 -04:00
Claude f40bb479e2
fix(libkernel): report the remaining time from sceKernelWaitSema
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 20:09:33 +00:00
jweidenh 3b32e54ed9 test(agc): skip partial collection when write watching is unavailable 2026-10-11 16:09:08 -04:00
jweidenh e5e8c232e8 fix(libc): preserve uncollected shared memory writes on Windows 2026-10-11 16:09:08 -04:00
jweidenh bf8a6bc2ff test(libc): cover partial shared write collection 2026-10-11 16:09:08 -04:00
hugodearaujo d5f11b156b fix(libSceUserService): report an unrestricted age level
sceUserServiceGetAgeLevel reported 0. On a PS5 (firmware 13.60) the
value is the age of the user's parental restriction (0, 7, 12 and 15
measured) and 0xFFFFFFFF without one, so 0 is a user restricted to age
0. A user who is not logged in returns 0x80960009 (not logged in) with or
without an output, before the null output check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:07:45 -03:00
Claude d358374ac8
fix(libc): throw for 16-bit wide scanf conversions on Linux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 20:07:20 +00:00
Arekatla Nishanth Chowdary c13d3b474a fix(build): reject MinGW compilers that select SjLj exceptions for the libraries
The libraries are built with -fno-asynchronous-unwind-tables and unwind
through their own DWARF tables. MinGW-w64 GCC 11.4 and 13.2 answer that
flag by switching to SjLj exceptions. Configuration succeeded and, with
13.2, the build stopped at the libc.prx link with undefined references
to __gxx_personality_sj0 and _Unwind_SjLj_Register, which does not name
the cause. Configuration now checks the exception model the flag selects
and stops with the supported toolchain's location.
2026-10-11 20:03:53 +00:00
fma-rc ba9f903e3f
feat(shader): implement s_subvector_loop_begin and s_subvector_loop_end 2026-10-11 22:03:26 +02:00
Claude 6b72296ef5
fix(libc): format 16-bit wide arguments in asprintf on Linux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 20:02:20 +00:00
Dean 0a8b1d32b1
Merge pull request #3415 from MarcZX100/codex/fix-windows-runtime-unwind-3411
test(libc): keep Windows exception cleanup coverage on guest frames
2026-10-12 08:59:34 +13:00
Santhosh Kumar 2ad916566f fix(libkernel_sys): return the resolver's error from symlink
symlink, added in #3491 while this branch was open, still resolved its
new path with ResolvePath_nid_no_patch, which now throws for an invalid
"..". Use ResolvePathError_nid_no_patch as link does, so
"missing/../x" returns ENOENT and "file/../x" ENOTDIR.

Reported by @Silverash-i8 on #3485.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:25:02 +05:30
Santhosh Kumar 17827dd9ab fix(filesystem): reject invalid parent traversal on Windows 2026-10-12 01:25:02 +05:30
milescoviello ad14190c13 fix(libc): resolve ".." in guest paths against the directory before it
Guest paths were normalized lexically before they reached the host, so
"missing/../file" and "file/../x" dropped the component before "..":
stat and open succeeded on the file, unlink deleted it and rmdir removed
a directory, where FreeBSD's lookup() resolves ".." with VOP_LOOKUP in
the directory reached so far and fails with ENOENT for a missing
component and ENOTDIR for a file. POSIX path resolution (XBD 4.13) says
the same.

".." is still collapsed lexically when the path before it is an existing
directory, so case-insensitive matching and aliases behave as before.
When it is not, the rest of the path is passed to the host unchanged and
the host resolves it. Linux then reports ENOENT or ENOTDIR as FreeBSD
does; Windows collapses ".." itself, so its results are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYhZu5HokHMo9mfi8QU83m
2026-10-12 01:24:53 +05:30
Claude 4a419397cb
fix(libkernel_sys): translate host errors to guest errno numbers
GuestError passed host error values up to 34 through and reported every
other value as EIO, so readlink failed with EIO for a name that is too
long or a symbolic link loop, and a host EAGAIN would have been reported
as the guest's EDEADLK. The values whose numbering differs are now
mapped to FreeBSD's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 19:50:38 +00:00
Hussein Kadhim aaf49fb40f fix(libc): compare strcasecmp and strncasecmp results after lowering
FreeBSD returns the difference of the lowercased bytes where the strings
differ, including where one of them ends. The guest wrappers returned the raw
difference of the terminator and the unfolded byte, so strcasecmp("ab", "A")
gave 66 instead of 98.
2026-10-11 19:49:35 +00:00
Hussein Kadhim 87e9c70157 fix(libkernel): recvfrom on a stream socket reports no sender address
FreeBSD's soreceive leaves the sender unset for a stream socket, so recvfrom
returns an address length of 0 (kern_recvit). The guest call formatted the empty
host address as a 28-byte AF_INET6 sockaddr and reported length 28. Report
length 0 when the host returns no AF_INET or AF_INET6 sender, as recvmsg does.
2026-10-11 19:48:51 +00:00
Hussein Kadhim 8db0f89e7b fix(libkernel): return SCE error codes from sceKernelClockGettime and sceKernelClockGetres
A thread CPU clock whose thread has finished made clock_gettime fail with errno EINVAL, but the sce wrappers passed the raw -1 through to the title. They now return the encoded errno like the other sce kernel calls.
2026-10-11 19:47:03 +00:00
PrintOrb cef97424a8 test(videoout): pin high-frame-rate display rejection 2026-10-11 14:46:14 -05:00
Dean 12c2266281
Merge pull request #3922 from oneandonlydean/up4/fix-implicit-lod-test-wqm
test(agc): enter whole quad mode in the implicit-LOD 1D sample test
2026-10-12 08:45:56 +13:00
Dean a061f5b5ac
Merge pull request #3510 from babyhuey/fix/libkernel-sys-symlink-windows
fix(libkernel_sys): create symlinks with CreateSymbolicLinkW on Windows
2026-10-12 08:45:52 +13:00
Dean 70eba72ad6
Merge pull request #3518 from Silverash-i8/fix/filesystem-test-directory-time
test(libkernel): don't require restoring the directory time on Windows
2026-10-12 08:45:48 +13:00
Dean f7d623528a
Merge pull request #3532 from MarcZX100/codex/srgb-compare-zero-3526
fix(shader): allow constant-zero sRGB comparisons
2026-10-12 08:45:45 +13:00
Hussein Kadhim 942b5945d1 fix(libkernel): leave the remaining time untouched when nanosleep completes
FreeBSD's kern_clock_nanosleep writes the remaining time only when the sleep is cut short. A completed sleep zeroed rmtp, so nanosleep(&ts, &ts) in a polling loop slept zero time from the second call on.
2026-10-11 19:45:27 +00:00
Scramblrrrr 2a58fb7997 fix(shader): preserve distinct definitions while folding phi inputs
Fold identical resolved values or equal immediate constants, retaining distinct branch-local SSA definitions. AI-assisted: yes (Codex).
2026-10-11 16:44:34 -03:00
Dean 4be9c25519
Merge pull request #3520 from MarcZX100/codex/gcc13-unwind-3459
fix(libc): resume host foreign exceptions with host unwinder
2026-10-12 08:37:59 +13:00
GalaxyGamingFR ede6fad8b2 fix(conventions): treat wrapped declarations as declarations
Check.duplicates reported a duplicate export for a hit in another
library unless that single grep line ended with a semicolon, so a
prototype wrapped over two lines was reported as a duplicate
definition. The hit file is now read at the head commit and the
existing function_body decides whether the hit is a definition.

The git grep pattern also used the GNU escapes \b and \s, which the
BSD regex library on macOS does not support, so the check never
matched there. The pattern now uses POSIX classes instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:20:36 -07:00
MarcZX100 cc7343daf5 fix(libc): clear fopen_s output on invalid arguments
(cherry picked from commit 387279ee941e5a203325852b24cdb87e2f835e43)
2026-10-11 19:16:51 +00:00
MarcZX100 fdf288f3fc fix(libc): return fclose failures to callers
(cherry picked from commit 610d6cdda098e9adfcd3814b52f8eba01caaa4d1)
2026-10-11 19:12:46 +00:00
MrMha 3742fa136e test(relinker): cover extra block bounds and header address overflow 2026-10-11 23:11:42 +04:00
AlxcBTW 99edf9435c fix(recompiler): read P10 of a flat input as the provoking vertex
A FLAT_SHADE input without pass-through that a pixel shader reads
through v_interp_mov_f32 P10 became an explicit per-vertex input and
read vertex 1 minus vertex 0. With the last provoking vertex the
pipeline then threw ("last provoking vertex with explicit per-vertex
flat interpolation is unsupported"), which stopped all three
ps5-opengl titles in the catalog.

ps5-opengl reads every flat input through P10 when GL's last-vertex
convention is in effect, and its driver passes the GL 4.6 CTS on a PS5
(#1413). Such a read now returns the provoking vertex's value, as P0
does, and only a P20 read keeps a flat input per vertex. The lane was
not measured on the console itself, so FragmentParameter records it
and a pipeline using the first provoking vertex throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:09:55 +02:00
Achraf Reyani 6eacac2e96 test(libkernel): check close of an unopened descriptor among the other bad-descriptor cases
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:08:23 +09:00
GalaxyGamingFR 08169eae25 fix(tools): ignore wrapped declarations in pr_overlap exports
exports() only checked whether the matching line ended with a semicolon, so a
prototype wrapped over several lines was counted as an implemented export and
two PRs adding the same forward declaration were flagged as overlapping. It now
joins the following added lines up to the first semicolon or brace and treats
the match as a declaration when the semicolon comes first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:03:55 -07:00
GalaxyGamingFR a89aa5c0d0 fix(progress): skip cells for rectangles without area
When squarify gave a group a sliver narrower than 2px, treemap passed cells a zero or negative width, so the row count became complex or divided by zero and render crashed. cells now returns no cells for rectangles without area. A regression test renders a 300 and 1 item split.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:00:10 -07:00
MarcZX100 b6f96f8e90 test(libkernel): extend existing credential regression coverage 2026-10-11 18:55:56 +00:00
Mouad-Scriptz-0 bc5bfd0ed6 feat(libkernel): export setuid, setreuid, setgroups and getgroups
`setuid`, `setreuid` and `setgroups` are absent imports of XPSemu
(PPSA97358) and PS5MC (PPSA99420) on `main`. The guest process is modelled
as root with ids 0, as `seteuid` and `setegid` already assume: `setuid`
accepts 0 and `setreuid` 0 or -1 per id and change nothing, any other id
throws. `setgroups` keeps the supplementary group list as FreeBSD's
`kern_setgroups` does (`NGROUPS_MAX` 1023, an empty list leaves the
effective group as the only entry, a first entry other than 0 throws) and
the new `getgroups` reports it. `guest_credentials` covers the accepted
ids, the default list, a set list, an empty list and the EINVAL/EFAULT
cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit d12b062074dcf64bff694800d77f7261adf6f59e)
2026-10-11 18:55:22 +00:00
MrMha 5740cd6c20 fix(build): separate UTF-8 and control-flow test registration 2026-10-11 22:52:58 +04:00
Avijit Singh 2e0dcd7f57 docs(agc): record write tracker shutdown ordering
Document why the Driver singleton must initialize the guest write tracker before its static construction completes on Windows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 00:19:27 +05:30
Avijit Singh 471d9eced2 fix(agc): keep write tracker alive through driver teardown
Initialize the guest write tracker during Driver construction so its function-local static is destroyed after Driver on process exit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-12 00:19:21 +05:30
Achraf Reyani b610642c61 fix(libkernel): close an unopened descriptor on Windows without the invalid-parameter report
close() of a descriptor that is not open calls _close, which raises the
UCRT invalid-parameter handler before returning EBADF. In a relinked title
that handler is libc's crash reporter, so an ordinary close of a closed
descriptor printed a FATAL report and every thread's stack. The call now
runs with the thread-local no-op handler, as dup and dup2 already do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:47:39 +09:00
Achraf Reyani 10740f85f9 refactor(libc): define the stack candidate helper beside ReportBacktrace
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:42:52 +09:00
Achraf Reyani cf2ca2b103 fix(libc): list stack return address candidates in Windows backtrace reports
The abort() and UCRT invalid-parameter reports capture the stack with
RtlCaptureStackBackTrace, which stops at the first frame without unwind
data (guest code, or our libraries built without asynchronous unwind
tables), so they often end two or three frames in, before any caller.
The fault report already scans the stack for code addresses; that scan
is now a helper the backtrace reports use as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:41:02 +09:00
PrintOrb 63434686bf fix(videoout): support permitted high-frame-rate output 2026-10-11 13:40:31 -05:00
Mouad-Scriptz-0 876c4ecacf test(recompiler): pin that an unwritten window register reads 0
Two more agc_driver_relative_indexing rows read a register of the window
the program never wrote, directly and through v_movrels_b32, and expect 0,
which the zeroed window array gives like an unwritten SSA register did;
the TechnicalDebt entry says the console's value is undefined.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 18:36:09 +00:00
Dean Galvin d9afe1078e test(agc): enter whole quad mode in the implicit-LOD 1D sample test
A pixel wave starts with only its covered pixels in EXEC, so a shader that
takes an implicit LOD has to run s_wqm first or the helper lanes of a partly
covered quad hold no coordinate. The test's pixel shader did not, which goes
unnoticed while its one triangle covers every quad whole. llvmpipe clips that
triangle at twice the viewport into three, and in the quads on the two inner
edges the helpers' zero coordinate gave the last mip instead of the expected
one.

The shader now starts with s_wqm_b64 exec, exec, as a compiled pixel shader
that samples with an implicit LOD does.
2026-10-12 07:35:46 +13:00
xXPBSXx 471e12e484 fix(libSceCesCs): drop the unused module target and move the TechnicalDebt line
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:35:09 +02:00
Jordan Hans b1104a2c65 fix(libSceSysmodule): recognize the libSceAgc internal module id 2026-10-11 18:33:48 +00:00
xXPBSXx 4eb3340dcb fix(rudp): throw from sceRudpGetMaxSegmentSize and justify the success of the pump calls
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:31:52 +02:00
Adrià Franch 1462312ebf docs(savedata): record the inferred sceSaveDataConvert contract 2026-10-11 20:28:50 +02:00
Mouad-Scriptz-0 f9fd0f125c fix(recompiler): give out-of-range relative vector accesses the measured semantics
M0 is unsigned, so an index at or past the window reads v0 and drops its
write, v_swaprel_b32 writes neither side when either is out of range, and
the window array starts zeroed like unwritten SSA registers; the window
load counts as a lane source so a wave64 program's second half keeps its
own registers. agc_driver_relative_indexing runs in wave32 and wave64 and
pins the rows measured on gfx1035 in the review of #3856, and the
TechnicalDebt entry states the measured behaviour, the window's end at the
last named register and the sizes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 18:28:02 +00:00
Alex 95988c9c34 fix(shader): flush f16 denormals in unary, frexp and conversion ops per the float mode
The f16 unary ops, v_frexp_mant_f16, v_frexp_exp_i16_f16, the norm
conversions and v_cvt_f32_f16 read denormal halves as they are and
rounded denormal results as they are, whatever the denormal field of
FLOAT_MODE says. On RDNA2 a clear bit 0 flushes a denormal half input
to its signed zero and a clear bit 1 flushes a denormal half result.

One shared rule now drives all of them, and v_ldexp_f16 uses it for its
input too.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 14:27:58 -04:00
Chad eedf7a2671 feat(savedata): implement sceSaveDataConvert
PPSA28416 calls it on its existing save at boot (after sceSaveDataDirNameSearch finds it) and aborted on the missing implementation. The call takes one parameter block: user id at +0, the directory name pointer at +8. Host saves have no size limit, so the conversion completes at once: an existing save returns OK, a missing one NOT_FOUND, an invalid name PARAMETER. The title polls sceSaveDataGetEventResult once afterwards and continues on 'no event'.
2026-10-11 13:23:58 -05:00
Tyler Westerberg 565e8e9c4a feat(libSceJson2): implement Object::find, Object::iterator::operator-> and String::compare
Goat Simulator 3 (PPSA04159) imports sce::Json::Object::find(String const&)
const (ehN1Biw3tw8), Object::iterator::operator->() const (EnesV4gXDtE) and
String::compare(char const*) const (Yfw63FVJgtU); without them the Windows
entry stub stops before the game starts with "unresolved ELF import
ehN1Biw3tw8".

find returns an iterator to the first pair whose key equals the argument,
or end(), using the same key match as Object::operator[]. operator->
returns the pair like operator*. compare orders the string against a C
string as std::string::compare does; a null argument throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:11:39 -04:00
Lexroid 5cd25dedbd fix(videoout): accept a buffer attribute change while a flip is pending
sceVideoOutSubmitChangeBufferAttribute2 threw when a buffer of the group
had a flip pending, and Marvel's Wolverine makes that call with flips in
the queue. A flip now takes its buffer group when it is reserved, in
submission order, so flips submitted before the change keep the
attributes their buffers were rendered with and later flips use the
new ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:06:04 +03:00
Adrià Franch c61f07409f test(shader): cover clamp alone and inf/NaN/fraction rows in v_cvt_i16_f16 output modifiers
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 19:58:44 +02:00
gookie d33dad00b8 fix(libSceXml): add an export-free libSceXml for titles that list it
PPSA19546 (Cookie Clicker) and PPSA34959 (The King is Watching) list
libSceXml.prx among their needed libraries but import nothing from it.
AnyPS5 builds no such library, so on Linux the dynamic loader stops both
before they run:

  ./eboot.elf: error while loading shared libraries: libSceXml.prx:
  cannot open shared object file: No such file or directory

On Windows the start-up stub has skipped a missing library that nothing
imports from since #3129; the Linux loader resolves DT_NEEDED itself
and cannot skip one. libSceXml now exists with no exports, like
libSceAgcVsh and libSceAudio, so it loads on both. A title that imports
from it still stops at the missing import.

Both titles now load and stop at their next missing import:
setSpecialFloatFormatType (PPSA19546, #3575) and sceHttpsFreeCaList
(PPSA34959, #3497).
2026-10-11 19:58:13 +02:00
Adrià Franch 07af520c1c docs(technical-debt): move the vieBRwlh1Lw entry off the end of Functional
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 19:58:11 +02:00
goncalompontes fa726efe94 test(shader): cover the VOP3 interpolation result and source modifiers
Extend the decode test to mul:4, div:2, -|v2|, -|v2| div:2, a p2
coordinate with neg and a non-zero attribute channel, a clamped p2, and
the mov form with clamp and mul:2. All 18 accepted words are the
assembler output (llvm-mc -mcpu=gfx1010).
2026-10-11 18:57:55 +01:00
Lorkydey 36d37a062a fix(libkernel): limit UTC-to-local DST output to 32 bits 2026-10-11 19:56:47 +02:00
Adrià Franch fdf8246f5e docs(architecture): describe APR and AMM command buffer queues 2026-10-11 19:56:25 +02:00
Ayan d700567008 perf(relinker): walk fallthrough instructions without queueing 2026-10-11 17:55:39 +00:00
SandstromPL 7f0c5d9d4d fix(relinker): accept the input's directory as a module directory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:21:34 +05:30
krishnaraya b3be79ffed fix(agc): keep FORCE_DEGAMMA paired when ANISO_OVERRIDE rebuilds a sampler
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:50:25 -04:00
Adrià Franch 896c958236 docs(technical-debt): record that sceSaveDataDirNameSearch rejects sort key 4
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 19:49:46 +02:00
virp-mta 302a8774ac feat(libc): implement drand48, lrand48, mrand48 and srand48 2026-10-11 21:48:56 +04:00
Semir Kabir e92547a7a1 feat(libkernel): wake each listed address in _umtx_op UMTX_OP_NWAKE_PRIVATE 2026-10-11 17:48:06 +00:00
Yunus Shaikh 9b1e1ecccd fix(savedata): sort sceSaveDataDirNameSearch results by the requested key and order
The search returned saves in host directory order and ignored the condition's key and order. A title that asks for the newest save first (modification time, descending) got whichever directory the host listed first: the alphabetically first on NTFS, an arbitrary one on Linux. Sort by directory name, user parameter or modification time, reverse for a descending order, and reject unknown keys and orders with the parameter error, as shadPS4 does.
2026-10-11 10:46:53 -07:00
Kikoarl 7714a5c2db feat(libSceSysmodule): register libSceShare module ID (0x10F) 2026-10-11 19:45:25 +02:00
Daan Dehing 780303049b test(agc): cover indexed rect-list draws with a partial last rectangle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:39:47 +02:00
billythemenace2 e2bfacefa3 feat(libSceRudp): declare the calls PPSA06888 imports
PPSA06888 stops on main at start-up because its bundled
Media/Plugins/SceRudp.prx imports sceRudpEnableInternalIOThread2,
sceRudpGetOption and sceRudpGetRemoteInfo, which no library exports.

The signatures are unknown, so they are declared without parameters and
throw. The title does not call them during start-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:39:22 +01:00
Zayd Zaari 4d15f9ef24 fix(rtc): recognize additional measured named time zones
Add thirteen offsets measured repeatedly on PS5 firmware 13.42, keeping DST names ahead of their shorter prefixes. Cover case folding, prefix matching and a second valid date.

Written with AI assistance; validated against real hardware and the guest RTC tests.
2026-10-11 17:36:41 +00:00
Lexroid fbb4d3771d fix(libkernel): give AMM buffers their own queue
One queue for APR and AMM buffers kept an AMM buffer behind an APR buffer
waiting on an address that the AMM buffer writes, so neither ran.
Marvel's Wolverine does this: an APR buffer waits on a counter that the
WriteAddress commands of later AMM buffers advance, and its loading
stopped. APR and AMM buffers now keep their order within their own queue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:32:11 +03:00
LeandroLP23 c27e67ceb5 test(libSceLibcInternal): run guest_force_tls_destructor on Windows
sceKernelGetModuleInfoFromAddr has a Windows path since 77ef75c1d, so
_sceLibcInternalForceTlsDestructor finds each dso's module there too.
The test takes the other module's address with GetProcAddress where
Linux uses dlsym(RTLD_NEXT), and the TechnicalDebt entry no longer says
the call throws on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:31:41 +02:00
nyavana 42062da564 docs(build): clarify when explicit libs target is required 2026-10-11 10:28:32 -07:00
Daan Dehing 0418aaaad2 fix(agc): draw the complete rectangles of a rect-list draw with a partial last one
A rect-list draw whose count is not a multiple of 3 threw "incomplete rect-list
primitive". Rect lists are drawn as patch lists of 3 control points, and Vulkan
generates floor(vertexCount/3) patches, so the draw now records as is and the
trailing 1 or 2 vertices are left out. Palworld (PPSA23126) draws 4 vertices x 9
instances as a rect list when character creation opens (#3832).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:28:27 +02:00
gookie 73866db755 fix(pad): report special ports as not connected in scePadOpen
scePadOpen returned the standard pad's handle for a special port
(type 2) as well, and scePadGetHandle found it there. Both ports then
read the one input queue, so a press queued between two frames could be
drained by the special port's read and never reach the standard port.
PPSA16827 (Harmony's Odyssey) opens both ports for the initial user and
reads both every frame, also polling controller information and device
class data for the special one.

Special ports now return DEVICE_NOT_CONNECTED (0x80920007) from
scePadOpen, as scePadOpenExt already does because the host has no
special controller, and scePadGetHandle has no handle for them.
TechnicalDebt's scePadOpenExt entry now covers both calls.

guest_pad opens a special port before and after the standard one and
expects DEVICE_NOT_CONNECTED, and DEVICE_NO_HANDLE from scePadGetHandle
for the special port while the standard handle stays valid. It fails on
main.

PPSA16827 over 130 s of its title screen: 6812 scePadRead, 3408
scePadGetControllerInformation and 3406 scePadDeviceClassParseData calls
before, two reads of the same queue per frame; 2702 reads, one
information call and no parse calls after.
2026-10-11 19:26:30 +02:00
omurc4 d40189d707 feat(libSceVideoOut): export sceVideoOutAddBufferAttributeOption
Elden Ring Nightreign (PPSA25380) imports the function, which no library
exported, so the title failed to load. The option is ORed into the buffer
attribute and a null attribute throws. Options other than 0 and 8 still
throw when the buffers are registered.
2026-10-11 13:26:22 -04:00
Mouad-Scriptz-0 f8ed012e3e perf(recompiler): keep relatively addressed vector registers in a window array
`v_movrels_b32`, `v_movreld_b32`, `v_movrelsd_b32`, `v_movrelsd_2_b32`
and `v_swaprel_b32` lowered to a compare-and-select chain over every
register from the base to the program's last allocated register, so a
program addressing 154 registers 104 times turned 3176 ISA words into
649,515 SPIR-V words that Intel's compiler did not finish. The registers
from the lowest relative base up now live in a function-scope array per
invocation (`LoadVectorWindow`/`StoreVectorWindow`), so an indexed access
is one load or store; plain accesses to those registers go through the
same array, DPP-modified relative writes keep their `DppUpdateU32` merge,
an index past the window reads 0 and drops its write, and programs
without relative addressing are unchanged. The same program recompiles
to 392,333 words with 4,992 selects instead of 32,383.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 17:26:18 +00:00
fdfawef324 58669dc134 fix(libc): write each log line in one call
mingw's fprintf writes an unbuffered stream a character at a time and
holds the stream's lock for the whole line. The APS5_LOG_* lines that
carry a RecompileRequest ("Shader ... could not be prepared after
registration", 15-20 KB each) took one WriteFile per character, and every
other thread writing to stderr waited behind them, guest calls that log
included. Demon's Souls (PPSA01342 v1.005, Windows) stops on a black
screen after two frames on main: a BPE job worker waits for the stderr
lock in sceSaveDataDirNameSearch's trace while the shader preparation
pool prints its dumps, so GameCoreLoop never finishes a frame.

The log macros now format the line into memory and write it with one
fwrite, as Driver::reportSkip does since 8cf2f6580. The UCRT writes an
unbuffered stream's fwrite as one even-length block and the last byte,
so a line takes at most two writes on Windows and one on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:23:21 -04:00
jackthereaper2006 2c769288c5 docs: record DOOM homebrew on Linux with an AMD GPU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:22:45 +05:00
hugodearaujo d1631862f5 fix(libkernel): report the operation mode the console reports
sceKernelGetOperationMode returned 0 for both values, which were
unknown. A payload on a PS5 (firmware 13.60) reads mode 2 and submode 0;
nothing past the two ints is written and the result register holds no
status, so the function now returns nothing. PPSA12544 logs both values
and ignores the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:20:54 -03:00
David f4424b5f1e feat(libSceAgc): implement the vieBRwlh1Lw interpolant mapping update
Hollow Knight Silksong (PPSA12544) imports libSceAgc NID vieBRwlh1Lw
(#699). Its name is unknown: it is not in aerolib, and the
sceAgcUpdateInterpolantMapping label other projects give it hashes to
SbuY2jN+axQ.

OpenAGC (src/game_compat.c at 3c7e807, sceAgcUnknownVieBRwlh1Lw) reads
it from FW 11.60 as the dbOlWdppb4o transform with the same (regs, gs,
ps) arguments, without the identity tail: it writes one register per
pixel shader input, none for a pixel shader without inputs, and rejects
a null pixel shader. It now shares the dbOlWdppb4o path and throws for
the rejected arguments.

For is_f16 1 and 3 inputs whose default_value and default_value_hi
differ, OpenAGC takes DEFAULT_VAL from default_value_hi, while KytyPS5,
sharpemu and dbOlWdppb4o here take it from default_value; these inputs
throw. On every other input the dbOlWdppb4o values equal OpenAGC's.

agc_interpolant_mapping runs the dbOlWdppb4o vectors and OpenAGC's
enhanced-mapping vectors through it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 20:16:47 +03:00
krishnaraya 8a0395381e fix(shader): accept DPP8 on v_pk_fmac_f16
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:16:11 -04:00
MarcZX100 42ac947f90 fix(agc): wake queue zero when workers become idle 2026-10-11 17:14:27 +00:00
lorkydey 329b9d63bb fix(relinker): normalize additional module directory paths 2026-10-11 19:12:52 +02:00
object05 6f527fa956 test(shader): accept the split fma sum in F32DenormalFlush
agc_driver_f32_denormal_flush fails on RADV RENOIR (Mesa 26.2.4):

  lane 20 no float mode v_fma_f32 v14, v4, v5, v6 is 0x00800000, expected 0x00ffffff

The driver lowers Fma to a multiply and an add: the compiled shader has
v_mad_f32 and no v_fma_f32. The product 0x1fffffff * 0x1fffffff is below
2^-126 and is flushed before 0x00800000 is added. Lane 20 is the only
row with a tiny product and a non-zero addend. v_fma_f32 and v_fmac_f32
fail on it in all three float modes; every other check passes.

When both return that sum, the two values are not checked. FmaRounding
already leaves out its fused forms on a device that splits fma.
2026-10-11 19:10:52 +02:00
MarcZX100 6693cd6301 fix(agc): scope idle writeback and test queue worker 2026-10-11 17:09:43 +00:00
gookie 28320acf2c perf(libkernel): read a loaded image's unwind tables once in sceKernelGetModuleInfoFromAddr
sceKernelGetModuleInfoFromAddr found the size of the image's .eh_frame
on every call by walking all of its CIE and FDE records, checking each
against every PT_LOAD header. The guest libc's unwinder calls it for
each frame it unwinds, so a title that unwinds often walked its whole
.eh_frame hundreds of times per second.

The tables read from a .eh_frame_hdr are now kept per header address
and reused while the image stays loaded. The cache is dropped whenever
dl_iterate_phdr reports that an object was unloaded (dlpi_subs), so an
address reused by another image is read again.

guest_module_info queries a module twice and expects the same tables,
then unloads it, loads it again and expects tables of the same size at
the same offset in the new image.

PPSA16827 (Harmony's Odyssey), title screen, over 500 calls per second
counted under gdb, which slows the title: the process used 9269 CPU
samples per 10 s, 53.7% of them in this walk, and 3306 with this change,
3.2% in the lookup. The title still runs at 27 FPS; its frame rate is
limited elsewhere.
2026-10-11 19:07:37 +02:00
xXPBSXx f854e52b26 docs: place the PPSA07411 TechnicalDebt entry away from the end of the file
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 19:06:38 +02:00
Semir Kabir 33c6e825ab feat(libSceUsbd): declare the device and handle calls for the no-device path 2026-10-11 10:06:27 -07:00
xXPBSXx ed0ea5e66b docs: place the PPSA30601 TechnicalDebt entry away from the end of the file
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 19:06:24 +02:00
winstrex 88e5a2e407 test(agc): split agc_driver_flat_apertures by shader instead of by row
Rows that run the same kernel at the same wave size compile the same
pipeline, so each part now takes whole groups of them, and the test is
split into fourteen parts. Each shader is compiled once per CI run
instead of in up to three parts at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:05:40 -03:00
xXPBSXx d7bf16a054 fix(exports): export the calls PPSA30601 imports
PPSA30601 (Resonance: A Plague Tale Legacy) fails to load without these imports that no library exports. Their signatures are unknown, so they are declared without parameters and throw until they are implemented. Adds a TechnicalDebt entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 19:02:18 +02:00
David-cmrg 6200b8c7b5 test(agc): split the gated dispatch producer spin into short dispatches 2026-10-11 19:01:47 +02:00
MarcZX100 7c2eba0a6d fix(libkernel): validate APR command payload sizes 2026-10-11 16:57:06 +00:00
aayushmishraaa f0bca23deb fix(relinker): reject input executables that are not x86-64
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:26:47 +05:30
MarcZX100 0a6247532e feat(relinker): trap exact SDK syscall stubs on request 2026-10-11 16:54:02 +00:00
xXPBSXx 34688d3a69 test(exports): drop the PPSA07411 export test
CONTRIBUTING asks for no tests that only check that a symbol is exported.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 18:51:54 +02:00
jweidenh 804fcb41e3 test(agc): keep storage probe callbacks out of buffer pools 2026-10-11 12:50:37 -04:00
jweidenh 9f567c227e test(agc): report recorder test Vulkan device 2026-10-11 12:49:32 -04:00
jweidenh 747321d0bb fix(agc): retain storage textures before recording initial uploads 2026-10-11 12:48:00 -04:00
jweidenh a1e01e1850 test(agc): cover storage upload lifetime before submission 2026-10-11 12:47:32 -04:00
Alex fba96d6422 fix(libc): asin(|x| > 1) returns the x86 default NaN and leaves errno unchanged
On main asin(2.0) returns 0x7ff8000000000000 and sets errno to 33;
FreeBSD msun (lib/msun/src/e_asin.c) returns 0xfff8000000000000 and
never sets errno. asin now handles |x| > 1 itself with quiet
comparisons, so a NaN input still raises no exception. For |x| <= 1
and for NaN the host function is still called.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 12:46:30 -04:00
screamm f51180973e feat(libSceAudioOut): implement sceAudioOutSysGetHdmiMonitorInfo
Surround Sound Studio (PPSA99051), catalog build on main a11c8f7f with
the flat-interpolation fix, stops 16 s in, before its first frame
(orishamir, #3581 comment 6109839314):

    sceAudioOutSysGetHdmiMonitorInfo not implemented

The call takes (type, out, size); out must be non-null, size exactly
0x180 and type 1 (HDMI) or 0x10 (sainsaji/PS5-Audio-Passthrough-Research
c3be9c2a, docs/FINDINGS.md section 3 and AGENTS.md:25, firmware 12.70).
Titles read the monitor name at +0x0B, the descriptor count at +0x94 and
8-byte descriptors from +0x98 (same, FINDINGS.md hardware log item 1 and
sample-app/src/platform/ps5/bitstream_out.cpp:92-128).

Audio reaches the host through SDL as PCM and there is no EDID, so type 1
with a 0x180-byte buffer reports a sink without a name or descriptors:
the buffer is zeroed and 0 is returned. Surround Sound Studio's
Passthrough page then lists no formats; EVO Player's code treats an empty
list like a negative return. A null buffer returns 0x80260004, as the
other AudioOut calls do. Type 0x10, other types and other sizes throw:
their results and error codes are not known.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 19:45:00 +03:00
Adrià Franch 28962787b3 docs(technical-debt): describe the v_sin and v_cos series fallback
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 18:44:14 +02:00
Semir Kabir 2124cfba5f feat(libkernel): report the process affinity from cpuset_getaffinity 2026-10-11 16:43:36 +00:00
Alex 2f5d166e2b fix(shader): accept output modifiers on v_cvt_i16_f16 and ignore them as the hardware does
v_cvt_i16_f16 with mul:2, mul:4, div:2 or clamp in the VOP3 encoding
stops the recompiler with "VOP3 source modifiers are not implemented".
On gfx1036 (Radeon 610M) the result is identical with and without
mul:2, mul:4, div:2 and clamp combined with mul:2, for all 66 measured
inputs; clamp on its own is not a measured case.

The decoder now accepts omod and clamp on v_cvt_i16_f16 and drops them,
as measured. Clamp without an output multiplier is accepted by the same
rule: clamp with mul:2 gives the same hardware result as mul:2 alone.
Matches 528 of 528 rows in two float modes, 0 differing.
v_cvt_u16_f16 is not measured and stays refused.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 12:40:48 -04:00
MarcZX100 d57d3f0000 fix(agc): store pending results when queues go idle 2026-10-11 16:39:36 +00:00
A-Akhil 3a3504850a
fix(shader): take v_sin_f32 and v_cos_f32 from an exact series where the driver's result is more than 4 ulp off 2026-10-11 22:06:22 +05:30
MarcZX100 63a45aacdf docs: document Windows Dozen driver workaround 2026-10-11 16:35:54 +00:00
xXPBSXx a68bc9dfdc fix(libkernel): allow sceKernelMprotect on committed host memory outside the guest registry
Thread stacks are host-private memory; the call threw instead of setting the native protection.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 18:35:35 +02:00
xXPBSXx a03afed4c3 fix(exports): export the calls PPSA07411 imports
PPSA07411 (Resident Evil 4) fails to load without these imports that no library exports. Their signatures are unknown, so they are declared without parameters and throw until they are implemented. Adds one test and a TechnicalDebt entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 18:35:00 +02:00
Eli Yarson 8d72065b68 docs: record DOOM homebrew on Linux with an NVIDIA GPU 2026-10-11 13:34:27 -03:00
MiniRML 7a82dd4879 chore: sync upstream before VideoOut driver review 2026-10-11 09:34:01 -07:00
Adrià Franch 38cb3b12d1 docs(technical-debt): record the single source of sceAgcAcbAtomicGds_0900
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 18:32:21 +02:00
Achraf Reyani 5027dcedc7 fix(shader): accept signed less-than in runtime SRT values
#2072 taught the SRT evaluator SLessThan32, but IsRuntimeUniformOp still
left it out, so the runtime validator rejected any descriptor dword computed
through a signed comparison before the evaluator could compute it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:32:12 +09:00
Semir Kabir 5f123fd1b2 feat(libSceFiber): add the underscore thread frame pointer export 2026-10-11 09:30:02 -07:00
fdfawef324 9d96752fcd fix(libkernel): let munmap succeed over a range with nothing mapped
munmap and sceKernelMunmap over a range in which no page is mapped
failed: munmap returned EINVAL and sceKernelMunmap let the registry's
exception escape. Both now return 0. The console returns 0 for
sceKernelMunmap of a range it just unmapped and of a never-mapped
address, and EINVAL only for a zero length, as measured by prosper's
console oracle (kernelx.golden.tsv, kx_fmem_unmap_again,
kx_fmem_munmap_unmapped).

The other half of #3196, a range with an unmapped page in the middle, is
already fixed on main by 04ed61957; the test covers both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:59:32 +05:30
Semir Kabir 54b9b93240 feat(libSceUlt): add underscore mutex and queue create exports 2026-10-11 09:29:28 -07:00
Lorkydey 43783f725c feat(libSceAgc): build versioned ACB atomic GDS commands 2026-10-11 18:28:46 +02:00
screamm b2da41e542 test(libkernel): accept host stacks above the AMM range in guest_amm_placement
On Windows, real thread stacks that exist before the guest arena is
reserved can sit near the arena top, so the AMM range correctly lands
9-60 GiB below it and the 1 GiB bound failed about 1 run in 10. The test
now requires that no free 64 GiB window exists above the AMM range.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 18:26:44 +02:00
jweidenh 503043ca00 fix(libkernel): run pthread key destructors before thread release 2026-10-11 12:21:40 -04:00
Hussein Kadhim d4f1303d47 test(libc): cover the strtod sign cases for every variant and atof 2026-10-11 21:51:31 +05:30
Hussein Kadhim 216ced6c27 fix(libc): return positive zero when strtod, strtof, strtold and wide variants perform no conversion 2026-10-11 21:51:20 +05:30
jweidenh 6ae2a784af test(libkernel): cover pthread key destructor lifetime 2026-10-11 12:20:59 -04:00
Romans Pokrovskis 1e40599f24 test(libkernel): verify app info missing metadata errors 2026-10-11 19:17:25 +03:00
jagrat Singh 86bd3b6621 feat(libSceAcm): implement sceAcm_FFT and sceAcm_Panner 2026-10-11 21:40:58 +05:30
Adrià Franch 4f013785dd docs(debt): record unverified scePadSetVibrationMode mode 3
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 18:06:39 +02:00
mariusyo07 1e3a9345f0 fix(pad): accept vibration mode 3
Broken Sword Reforged (PPSA21480) calls scePadSetVibrationMode(handle, 3) after
scePadOpen and treats a failure as fatal (ps5_controls.cpp:19 "Sony call failed
with code 80920001"). Modes up to 3 are accepted, 4 and above stay invalid.

Co-Authored-By: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com>
2026-10-11 18:02:39 +02:00
MrMha 656005c2a4 fix(shader): handle cache file allocation failures 2026-10-11 19:57:45 +04:00
MrMha 474c2b9ff1 fix(libkernel): reject malformed UTF-8 in param JSON 2026-10-11 19:56:55 +04:00
MrMha e5c280fed4 fix(codegen): reject rewrites inside instructions 2026-10-11 19:56:00 +04:00
Hussein Kadhim 700f017eb6 test(libkernel): check that timed-out rwlock reads leave no reader count 2026-10-11 21:25:20 +05:30
Hussein Kadhim b02881cf0e fix(libkernel): fail pthread_rwlock_unlock with EPERM when the rwlock is not held
scePthreadRwlockUnlock called unlock_shared on the host mutex whenever the
caller was not the writer, which is undefined behaviour for an unlocked rwlock
or one write-locked by another thread. Track the reader count and return
EPERM like FreeBSD libthr when the caller does not own the write lock and no
read lock is held.
2026-10-11 21:25:20 +05:30
MrMha b443760ca4 fix(relinker): validate file-backed unwind record ranges 2026-10-11 19:55:09 +04:00
Lorkydey d71c51c22d feat(libkernel): implement wait through guest waitpid 2026-10-11 17:53:21 +02:00
MrMha 653eb704c2 fix(relinker): validate complete allocated section ranges 2026-10-11 19:52:18 +04:00
MrMha d85d1c268f fix(relinker): validate program layout ranges before writing 2026-10-11 19:51:17 +04:00
David 60a7f28112 feat(libkernel): implement sceKernelAioSetParam
Dying Light 2 (PPSA02262) imports sceKernelAioSetParam (9WK-vhNXimw) from
its eboot. In #1794 tv7 reported on main b5f5362d3 + #2129 (2026-10-10):

  FAIL: unresolved ELF import -q-vbO859Tw from libSceVideoOut.prx

with "12 other imports are still unresolved on `main`. In the eboot,
`-q-vbO859Tw`, `GTfJ64qFCPw`, `vwtVpHQKelI` (no known names),
`sceKernelAioSetParam` and `sceNpWebApi2GetMemoryPoolStats`." The import
is observed; its position in the loader queue after the nameless NIDs is
predicted.

The function fills one SceKernelAioSchedulingParam (five 4-byte fields,
20 bytes): Orbital cc408367 tools/ida/db_types.json:1103, SharpProspero
5dfdb4b0 Interop/Kernel/KernelAio.cs ("Sets every field of param at
once") and ampr_emu cfa85df3 ps5/include/sce/_fs.h agree on
(param, schedulingWindowSize, delayedCountLimit, enableSplit, splitSize,
splitChunkSize). No source gives an error code, so a null struct and
values outside SharpProspero's maximums (window and delayed count 0..128,
split flag 0 or 1, sizes up to 0x1000000) throw. The engine does not use
the settings, as sceKernelAioInitializeImpl ignores its struct; this is
recorded in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit e45a2b950afe594212db2764529ccae32f84be8c)
2026-10-11 15:50:42 +00:00
Jan Šlégl e753080391 fix(libkernel): count guest module segments against the flexible memory budget
sceKernelAvailableFlexibleMemorySize and the flexible maps counted only
explicit flexible mappings, so the full 448 MiB was reported while the
title's executable and modules were loaded. A title that derives its code
and data size from the budget minus the available size got an unsigned
underflow.

The segments of the main executable and of every .guest.prx module that
the title's ELF gives permissions now count, rounded to 16 KiB pages, as
shadPS4 maps every non-system module segment as flexible memory. The
relinker's own blocks and the host system libraries do not count. The
charge ends when a module is unloaded.

Refs #2883

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-11 17:48:05 +02:00
Alex b00efdb261 fix(shader): accept abs, neg and op_sel source modifiers on v_cvt_pknorm_i16_f16 and v_cvt_pknorm_u16_f16
v_cvt_pknorm_i16_f16 and v_cvt_pknorm_u16_f16 with |x|, -x or op_sel in
the VOP3 encoding stop the recompiler with "VOP3 source modifiers are
not implemented", although the RDNA2 hardware executes them.

These two opcodes now use the two-source f16 modifier path of
v_pack_b32_f16: op_sel picks the high half of either source, then abs
and neg apply. Other op_sel bits, clamp and omod are still refused.
Matches 15632 of 15632 rows measured on gfx1036 (Radeon 610M) in two
float modes, 0 differing.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 11:45:26 -04:00
Tharun Balaji a0a7155964 test(libkernel): cover creat error cases
Carry the additional GuestFilesystem checks from issue #3303 after its implementation landed on main. The declaration already exists on main, so keep one prototype.
2026-10-11 15:43:40 +00:00
overlordxrz-source 4891d625af feat(libSceNet): export sce_net_in6addr_linklocal_allnodes
Co-authored-by: eliasbruno124-dev <230422461+eliasbruno124-dev@users.noreply.github.com>
2026-10-11 11:41:05 -04:00
MarcZX100 e56a727375 feat(build): support Linux AddressSanitizer builds 2026-10-11 15:40:36 +00:00
MarcZX100 776cff0efb fix(libSceHttp): use native Windows condition waits
Use an SRW lock and native Windows condition variable for epoll waits, preserving the shared handle lifecycle. This avoids the scheduler-tick overshoot measured with std::condition_variable on Windows.

Suggested-by: winstrex
2026-10-11 15:40:29 +00:00
David 4c7d83a2bf feat(libSceHttp): implement sceHttpAbortWaitRequest and the unlimited sceHttpWaitRequest
Deathloop (PPSA01670) imports sceHttpAbortWaitRequest; Planet Coaster
(PPSA01736) and Palworld import sceHttpWaitRequest.

Epoll handles are kept in a registry with an abort flag, a destroyed flag
and a condition variable. A wait with a negative timeout blocks until
sceHttpAbortWaitRequest, sceHttpDestroyEpoll or the sceHttpTerm of the
last context wakes it; a bounded wait still returns 0 events. An abort
stays set and makes every later wait return SCE_HTTP_ERROR_ABORTED
(0x80431080); a wait woken by destroy or term returns 0 events.
sceHttpDestroyEpoll no longer frees a handle a waiter is blocked on.
sceHttpInit registers its context, and the epoll calls and sceHttpTerm
return BEFORE_INIT without a live context and INVALID_ID for an unknown
context or handle.

Behaviour and error codes: shadPS4 src/core/libraries/network/http.cpp
and http_error.h at a8a70da595da2a96e0410309472ba4a7eb558144.
Signature (void* eh): Orbital tools/ida/db_types.json at
b321fcdbd700cc02da1cb1ad25412781d5ec73c6 and SharpProspero
src/SharpProspero/Interop/Net/Http.cs at
60977b29103452b9681ae10c7a9011d44965bf16.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 766997df3f8329fd6e8e7aac2b5d83daf88c8292)
2026-10-11 15:40:17 +00:00
Darryl Fernandes c2f16e0e4d fix(libkernel): support RUSAGE_CHILDREN in getrusage
Co-authored-by: milescoviello <kitslayer29@gmail.com>
2026-10-11 11:39:12 -04:00
Utku Halis 99ddfa762a fix(libc): track never-collected pages in the macOS write watch
On macOS, GuestWriteWatchCollectFresh reported nothing and returned true, so
MarkWritten took pages no collection had armed yet for clean, and they stayed
writable without being tracked. GuestWriteWatchCollectArmed was a full collect,
which also took those pages.

Pages now carry a fresh bit from registration until a collection takes them, as
the Linux watch keeps its fresh ranges: CollectFresh reports and arms only fresh
pages, CollectArmed skips them, and Collect takes both. Protection changes, host
writes and faults keep the bit.

The write_watch fresh and armed tests check both collections.
2026-10-11 18:34:59 +03:00
Adrià Franch 6293e6ae63 docs(technical-debt): cover the single-item NpEntitlementAccess info requests 2026-10-11 17:34:43 +02:00
Adrià Franch 86da3e9d74 fix(libc): include cerrno in Math.cpp 2026-10-11 17:34:21 +02:00
JAB-dev e127a525d1 feat(libSceFont): implement sceFontCharacterGetSyllableStringState
The call was an unimplemented stub. It now writes syllable state 0 and
returns OK for every character outside the Thai block, where a PS4
firmware 11.00 libSceFont measures 1, 3 or 4; Thai characters throw as
not implemented. A null character or result returns
SCE_FONT_ERROR_INVALID_PARAMETER, and a null character writes 0 to a
non-null result, as measured. The signature follows SharpProspero.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 17:32:23 +02:00
MrMha cf1195ad20 fix(hw-oracle): narrow cache PR and normalize runtime paths 2026-10-11 19:31:39 +04:00
MrMha 19344d661a test(packaging): restore cwd before temporary cleanup 2026-10-11 19:30:59 +04:00
virp-mta e6dcb46f3a feat(libSceNpEntitlementAccess): implement offline entitlement info requests 2026-10-11 19:30:34 +04:00
MrMha 2f6db82da7 fix(nid-names): normalize Windows inventory paths 2026-10-11 19:30:28 +04:00
exefer 3ae2583802 fix(libkernel): select descriptors that are not sockets 2026-10-11 17:25:32 +02:00
Alex 1a6f6a9f13 fix(libc): match FreeBSD asinf errno
asinf returned 0xffc00000 (errno 33) for 2.0 (0x40000000), where FreeBSD
lib/msun/src/math.h returns 0xffc00000 (errno 0).

It now returns the FreeBSD result for that case. A guest test covers it
and fails on main.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 11:22:51 -04:00
Lorkydey 6744880450 fix(libc): parse atoi through guest-width strtol 2026-10-11 17:20:39 +02:00
JAB-dev b576273225 fix(libSceFont): return the letter step of sceFontWritingRefersRenderStepCharacter through a pointer
The second argument is an out pointer to the writing's letter step, as
KytyPS5 and the SharpProspero bindings declare it. It was filled as a
letter step struct, which wrote 64 bytes over the caller's 8-byte
pointer. The letter step now lives in the writing and the call stores
its address, or null when there is no current step.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 17:12:47 +02:00
David dc022d8418 fix(libkernel): let a guest unlink and rename files it has open on Windows
FreeBSD removes or renames a file that is still open; the descriptor stays usable. _wopen opens without FILE_SHARE_DELETE, so sceKernelUnlink returned EACCES and rename failed while the guest held a descriptor. sceKernelOpen now opens through CreateFileW with delete sharing and keeps the flag, mode and error mapping of _wopen.

(cherry picked from commit 2f5ada5c86a427505804f22def209e054b3571e4)
2026-10-11 15:11:38 +00:00
virp-mta 4b91755d9a feat(libSceSigninDialog): complete offline sign-in dialog lifecycle 2026-10-11 19:11:37 +04:00
Adrià Franch 8b73fe7a76 fix(stubgen): give new output files the default umask permissions 2026-10-11 17:11:35 +02:00
Ondra97 1f34f6e8d4 fix(relinker): preserve inputs when writing desktop assets 2026-10-11 17:11:26 +02:00
Adrià Franch a5465007fa test(conventions): merge duplicate import 2026-10-11 17:10:33 +02:00
Zurisen 3c6c5d5331 fix(libkernel): reserve the AMM ranges below host regions at the top of the guest arena
The AMM ranges were reserved at the last 64 GiB of the guest arena and
the reservation threw when that window was not free. On Windows the
stacks of the threads that exist before the arena is reserved (the main
thread and the loader's workers) are placed at random addresses and are
left in the arena as host regions; when one fell in the last 64 GiB, the
first AMM use threw "fixed guest mapping ... overlaps a host region in
the guest arena". Reserve the highest free 64 GiB window instead: the
last 64 GiB when it is free, and the window just below an occupied part
of it otherwise.
2026-10-11 17:09:12 +02:00
Alex 9ff132d9a5 fix(shader): accept the clamp bit on VOP3 float compares
The decoder throws "VOP3 source modifiers are not implemented" for
VOP3-encoded float compares (v_cmp_*_f16/f32/f64) that set the clamp
bit, so shaders using them fail to compile.

On RDNA2 hardware the clamp bit does not change the result of a float
compare: the measured results with and without it are the same. The
decoder now accepts the bit on float compares; clamp on other carry-out
and scalar-destination opcodes still throws.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 11:04:38 -04:00
goncalompontes 61d4494863 fix(shader): accept the inline constant third source of VOP3 interpolation
The assembler encodes the unused third source of the VOP3-encoded
interpolation forms as the inline constant 0 (src2 = 0x80, bit 25 of the
second word), which the decoder refused. Accept that encoding and refuse
any other third source. The decode test now uses the assembler words for
every accepted form and keeps the refusals one field away from a valid
word.
2026-10-11 16:03:46 +01:00
David 9ac583bddd feat(libSceAudioIn): implement sceAudioInHqOpen and sceAudioInAsyncOpen
Both open the same SDL capture port as sceAudioInOpen, so Input,
GetSilentState and Close work on their handles. HqOpen accepts only a
128-sample grain at 48 kHz (SharpProspero, KytyPS5); AsyncOpen returns
INVALID_SIZE above 384 samples (SharpProspero). Values the sources
disagree on throw. Format 0x10 still throws: only KytyPS5 accepts it.

Imported by FMOD-based titles, The Smurfs Dreams (PPSA21607) and Astro
Bot (PPSA21564); Ghost of Yotei (PPSA26344) calls sceAudioInOpen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 16bfdf928d0a2da0b4473db2633a2e270538cbf5)
2026-10-11 15:03:16 +00:00
Nuno Silva 199225225f test(shader): cover SRT read use patching 2026-10-11 16:02:49 +01:00
Adrià Franch c81ee9288c docs(technical-debt): record fstatvfs deviations from FreeBSD 2026-10-11 17:01:55 +02:00
Claude 54e5aad214
test(libkernel): skip the read-only truncate cases when running as root
Root ignores the file mode, so truncating a file with only the owner
read bit succeeds and guest_truncate aborted when the suite ran as root,
as it does in containers. The read-only cases now run only for other
users and the test says on stderr when it skips them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 14:59:10 +00:00
MarcZX100 f942de360e test(libc): keep Windows unwind coverage within guest frames 2026-10-11 14:58:39 +00:00
Adrià Franch 9758607197 docs(technical-debt): record invalid-id returns of the other Http2 handle exports 2026-10-11 16:57:18 +02:00
Tharun Balaji c426143712 fix(libSceHttp2): clear completion queues for cascade-deleted requests
sceHttp2DeleteRequest erased the request's completion queue, but
sceHttp2DeleteTemplate and sceHttp2Term removed descendant request
handles through ReleaseOwnedHandles without clearing their completion
queues. A request that completed asynchronously before its template or
context was deleted kept a stale completion that sceHttp2WaitAsync could
still consume.

ReleaseOwnedHandles now returns every transitively removed handle id, and
DeleteTemplate and Term erase the completion queue of each removed
request. CompleteAsync validates that the request is live while holding
the handle lock and inserts the completion under it, so a send that races
a deletion either returns the invalid-id error without queuing or is
erased by the deletion; a completion is no longer re-created after a
deletion returns. The only lock nesting stays handles before completions,
and no mutex is held while the user event is triggered.

GuestHttp2 covers a queued completion before sceHttp2DeleteTemplate and
before sceHttp2Term: the completion is no longer consumable, a late send
returns the invalid-id error without queuing, and the removed handles are
rejected.
2026-10-11 16:57:12 +02:00
Tharun Balaji 4337b43f54 fix(libSceHttp2): validate SSL setter handles 2026-10-11 16:57:12 +02:00
Claude bd0998a7a8
fix(build): keep libc.prx needed by every executable that links a prx
Ubuntu's GCC links with --as-needed, so a test that calls nothing in
libc.prx directly dropped it from DT_NEEDED and satisfied the prx
libraries' __cxa_* and __gxx_personality_v0 references from the static
libstdc++ instead. Those copies interpose libc.prx's, so exceptions
thrown inside the prx libraries were searched by libgcc and resumed by
the guest unwinder, which aborted guest_kernel_stack_protect. libc now
propagates to every consumer of a prx with --no-as-needed on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 14:56:57 +00:00
lorkydey 5bd43e3e8e build(libc): register filesystem statistics source separately 2026-10-11 16:55:03 +02:00
QRMOE a06728b566
docs(libc): update remaining strftime gaps
Record literal handling while retaining unimplemented padding and timezone gaps.

AI-assisted: yes
2026-10-11 16:53:00 +02:00
Ori Shamir 3f4438dcca fix(pad): keep partial L2/R2 values from a controller
An SDL controller sets the L2/R2 bit whenever its trigger axis is above
zero, and BuildData then reported 255 for any set bit, so a partly
pressed trigger read as fully pressed. Report the analog value whenever
there is one; 255 remains for an injected press and for a bit without
an analog value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:52:56 +03:00
QRMOE 90a14e6a1f
test(libc): cover strftime literal conversions
Exercise unknown, repeated and incomplete conversions, percent escaping and buffer boundaries.

AI-assisted: yes
2026-10-11 16:52:30 +02:00
QRMOE 1b9179501f
fix(libc): preserve strftime literal conversions
Normalize FreeBSD 11.4 literal conversions before host formatting.

AI-assisted: yes
2026-10-11 16:51:42 +02:00
Dean Galvin c1287d73c5 fix(agc): leave the depth surface out when no enabled test has its plane
DecodeState bound the depth surface whenever DB_DEPTH_CONTROL enabled a
depth, stencil or depth bounds test and either plane was valid. A stencil
test beside a depth-only surface (DB_STENCIL_INFO format invalid, depth
test off) tests nothing, but the surface was still attached and the
render extent was clamped to it. A draw into a 1920x1080 target with a
960x540 depth surface left bound then covered only the top-left quarter.

A test whose plane is present but invalid no longer binds the surface.
Such a draw renders without a depth attachment, as it already does when
both planes are invalid. DrawRejection follows the same rule.
2026-10-12 03:43:27 +13:00
Adrià Franch a1d11ba4a2 test(relinker): drop unregistered evidence script for export aliases
The script needs a stock and a patched converter binary as arguments and is not
run by ctest; the C++ test covers the same cases.
2026-10-11 16:43:10 +02:00
Oguzhan Ozdemir 5ea9ce2e40 fix(relinker): allow identical Windows function export aliases 2026-10-11 16:43:07 +02:00
xXPBSXx abf6f06be4 fix(rudp): provide the calls PPSA03490 still lacks
PPSA03490 (Demon Slayer) imports sceRudpGetMaxSegmentSize, sceRudpProcessEvents, sceRudpNetFlush and sceRudpNetReceived, which no library exports. The first three answer by the library's initialised state; sceRudpNetReceived is declared without an implementation because its signature is unknown. Adds one test and TechnicalDebt entries.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 16:37:32 +02:00
LeandroLP23 d668b7c2b1 fix(shader): check NaN on the bits for ordered less-than and greater-than
On the AMD Windows driver 32.0.13058.8001 (Radeon 860M), a NaN compared
less than +infinity, or +infinity greater than a NaN, gives 1 when the
infinity reaches the shader as a constant, as in
agc_driver_f32_compare_constant's register operand case (#3536). The
same driver returns 1 for a NaN in an ordered not-equal (#825), which is
presumably what its compiler turns these compares into. FPOrdLessThan32
and FPOrdGreaterThan32 now AND their result with the integer NaN check
FPOrdNotEqual32 already uses, which gives the same result for every
input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1cfbde5d69fe3b5c0aa482d4ff3551f0e87c3915)
2026-10-11 14:36:11 +00:00
MarcZX100 b0d7d8254f fix(shader): handle NaN below positive infinity 2026-10-11 14:36:11 +00:00
MarcZX100 e7c20b3033 feat(libc): export isnanf and __signbitl 2026-10-11 14:35:01 +00:00
Claude d7f1a6d3d5
fix(libkernel): translate host errno in the file functions' SCE errors
SceErrorFromErrno in the libkernel file functions passed host errno
values 1-34 through and turned every other value into EIO. Linux numbers
EAGAIN 11, which is FreeBSD's EDEADLK, so a read from an empty
non-blocking pipe returned SCE_KERNEL_ERROR_EDEADLK, and ENAMETOOLONG,
ELOOP, ENOTEMPTY, EDQUOT and EOVERFLOW, whose host values differ from
FreeBSD's, all became EIO.

Map those host values to the guest's FreeBSD numbers, as
SceIoErrorFromErrno in Open.cpp already does for EAGAIN, EDEADLK,
EDQUOT and EOVERFLOW. The guest constants the callers pass are all at
most 34 and never 11, or GUEST_ENOTEMPTY, so they are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 14:32:44 +00:00
Achraf Reyani 27599ccfbf fix(libc): align mspace allocations to 32 bytes
Clang's PS4 and PS5 targets set the default new alignment and the suitable
alignment to 32 bytes, so PS5 code may store to a fresh mspace block with
32-byte-aligned AVX instructions, as the guest heap already allows since
#1621. The mspace allocator aligned blocks to 16 bytes only. Every mspace
allocation is now aligned to at least 32 bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:32:41 +09:00
alfalfa-star 31de083006 test(agc): require every compiled mesh program to read NumWorkgroups
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:30:37 +02:00
alfalfa-star 4d0d3c06e8 fix(recompiler): read NumWorkgroups in every mesh shader so RADV sizes its user data
RADV (Mesa 26.2.4, GFX12) updates the user SGPR count and draw-id flag
it uses for a mesh dispatch only when the bound mesh shader has the
grid-size/draw-id slot. A mesh shader reading neither NumWorkgroups nor
DrawIndex keeps the previous vertex pipeline's values: the dispatch
opens a 3-register SET_SH_REG, writes one value, and the CP parses the
following DISPATCH_MESH_DIRECT as register data. The gfx ring then
times out and the GPU is reset with VRAM lost.

Kena: Bridge of Spirits (PPSA01802) hits this on its layered volume
draws, which interleave with vertex draws in one command buffer.
Confirmed with RADV_DEBUG=hang (the dispatch header shows up as
SPI_SHADER_USER_DATA_GS_4) and the CP header history in the amdgpu
devcoredump.

Every mesh shader now loads NumWorkgroups.x and sets zero vertices
when it is 0, which no dispatch produces, so RADV gives it the
grid-size slot and writes as many values as it announces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:30:37 +02:00
MrMha 0ffd244af2 fix(ci): preserve test discovery and skip diagnostics 2026-10-11 18:25:36 +04:00
QRMOE 97409a6d08
test(libc): cover dirname result length boundaries
Cover 16 paths with long leaves, exact-fit and overlong directory results, repeated separators, input preservation and guest errno. The regression reports 12 failures on unchanged main and passes with the accompanying fix.

AI-assisted: yes
2026-10-11 16:25:14 +02:00
MrMha 563b4738a5 fix(hw-oracle): invalidate cached builds when inputs change 2026-10-11 18:24:42 +04:00
MrMha 5ccc11642f fix(packaging): validate and stage release archives 2026-10-11 18:23:59 +04:00
QRMOE f133aaa4b0
fix(libc): check dirname result length
Find the directory component before checking the result buffer limit, matching FreeBSD 11.4. Preserve input and guest errno on success; overlong directory results still report ENAMETOOLONG.

AI-assisted: yes
2026-10-11 16:23:53 +02:00
Adrià Franch 4abf052341 docs(debt): record zero default for unexported pixel inputs 2026-10-11 16:23:32 +02:00
MrMha 83be8dfb27 fix(stubgen): protect input files and keep stdout valid C++ 2026-10-11 18:23:13 +04:00
MrMha 08b1b7808a fix(nid-names): ignore comments and literals in symbol inventories 2026-10-11 18:22:21 +04:00
MrMha 14bbb1e00f fix(pr-overlap): bound explicit dependency declarations 2026-10-11 18:21:44 +04:00
Alberto Ruiz 029430690f test(json2): destroy the value before constructing over it
ValueClear constructs a Value, then calls the Value(const Object&)
constructor on the same object. The constructor allocates a new node and
overwrites the pointer, so the first node (56 bytes) is never freed.
LeakSanitizer reports it; destroy the value first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5WJS4ZdQynAJesCZKH5hb
2026-10-11 16:21:15 +02:00
MrMha 45f349df9b fix(conventions): handle unusual Git paths and escaped links 2026-10-11 18:21:09 +04:00
xXPBSXx 66165443c0 feat(libSceCesCs): add sceCesRefersUcsProfileCp1251 and sceCesMbcsUcsContextInit
PPSA15246 (Teardown) imports both from the module-named libSceCesCs-module and
stops at the loader without them. Cp1251 joins Cp1252 in sceCesSbcToUtf8 and
sceCesUtf8ToSbc; the context initializer succeeds without storing anything
because its layout is unknown (listed in TechnicalDebt.md).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 16:20:47 +02:00
MrMha d6bc502765 fix(import-audit): validate ELF and PE exports before reporting 2026-10-11 18:20:18 +04:00
Nuno Silva baf376862f perf(shader): avoid copying SRT read uses 2026-10-11 15:19:53 +01:00
XairRrR 2f140cb8b0 fix(agc): read zero for pixel inputs of parameters the vertex stage does not export
A pixel input whose SPI_PS_INPUT_CNTL offset names a parameter the
previous stage does not export failed validation ("graphics interfaces
disagree"), so the draw threw. No export writes that parameter slot for
the draw. radeonsi programs a pixel input without a matching vertex
output as OFFSET 0x20 with DEFAULT_VAL 0, so that it reads (0, 0, 0, 0)
(SI_PS_INPUT_CNTL_UNUSED in si_shader.h, applied in si_shader.c), and
rect-list draws already pass zero for such inputs.

Before the pixel stage of a draw is prepared, inputs that read a
parameter the previous stage's program does not export now read zero:
OFFSET bit 5 is set, DEFAULT_VAL and FLAT_SHADE are cleared, and an FP16
input also reads zero in its high half (USE_DEFAULT_ATTR1 set,
DEFAULT_VAL_ATTR1 cleared). Inputs that already read a default value
are unchanged.

Fixes #2975.
2026-10-11 16:14:12 +02:00
Alex 632338cd65 fix(libc): fmod leaves errno unchanged
fmod set errno (33) for 1.0, 0.0. FreeBSD msun never sets errno and
reports errors through floating-point exceptions only, so errno is now
saved and restored around the host call.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 10:07:19 -04:00
Celegans12 76fa2beceb perf(recompiler): reuse sorted sets for iteration selection merges
Seed each iteration-selection update from its first eligible successor
instead of rebuilding and intersecting the universe of block IDs.
Reuse the existing in-place intersection and sorted-insertion helpers
while preserving the original empty-successor and fixed-point behavior.
Keep a cache-neutral switch for same-binary output and timing comparisons.
Run the existing structurizer and control-flow fixtures in a separate
process with this optimization disabled as well as in their default mode.
2026-10-11 16:06:57 +02:00
Celegans12 f32bbf2e9e fix(cache): replace entries while Windows readers retain old files
Publish Windows cache entries with the POSIX rename operation so an
open delete-sharing reader keeps its original file after replacement.
Close the rename handle before returning and retain the existing
fallback only when the extended operation is unsupported.
Exercise old and new reader contents, deletion lifetime and temporary
file cleanup in the registered disk-cache regression on both platforms.
2026-10-11 16:03:37 +02:00
Celegans12 09894076d4 fix(agc): own resolved dispatch state through thread exit
The resolved-dispatch map was a nontrivial thread_local object.
MinGW can run its destructor after emutls frees the backing storage,
causing an access violation when a queue worker exits.
Use the existing ThreadOwned helper to destroy the heap-owned map
through its pthread key while keeping a trivial TLS pointer.
Reject FATAL output in both draw-cache test modes so a background
shutdown failure cannot pass only because the process returns zero.
2026-10-11 16:01:34 +02:00
EdouardSence b4b2e8843a docs(TechnicalDebt): list sceRazorCpuPushMarker under silent stubs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:59:53 +02:00
Scramblrrrr 363d17985e fix(relinker): lower legacy packed reciprocal register instructions 2026-10-11 10:58:14 -03:00
lorkydey 1ead4a120c feat(libc): implement guest fstatvfs volume statistics 2026-10-11 15:57:20 +02:00
Scramblrrrr 56d08f2547 fix(agc): exclude host arena holes from write-watch proofs 2026-10-11 10:55:48 -03:00
QRMOE 10e822cf04
test(libkernel): cover omitted clock resolution
Cover 20 clock IDs, preserved guest errno, non-null unsupported clocks and the SCE null-output fault. The regression fails against main and passes with the accompanying fix.

AI-assisted: yes
2026-10-11 15:53:15 +02:00
Ahir 48dcaace78 fix(shader): lock recompiler shared mutexes once when created
winpthreads initializes a statically initialized rwlock on its first
lock and fails a concurrent first lock with EINVAL, which
std::shared_mutex ignores, so two threads can hold the lock at once.
The source, binding plan and specialized module caches take their
first locks from several threads, so their mutexes now take and
release the lock in their constructor, as guest rwlocks do.

The GuestWriteWatch mutex the technical debt entry also named is in
the Linux-only watch, so it is not affected.
2026-10-11 19:22:13 +05:30
QRMOE 7fdc5b4528
fix(libkernel): honor null clock_getres output
Return success for a null POSIX resolution output before inspecting the clock ID, matching FreeBSD 11.4 sys_clock_getres.

AI-assisted: yes
2026-10-11 15:51:43 +02:00
Sanjaysrinivas 3d31a8464a fix(agc): reclaim idle buffers on allocation OOM 2026-10-11 15:50:46 +02:00
fablevoid 17e03d3c0a fix(libc): fail fgets with a size of 0 or less like FreeBSD
The guest fgets handed the size straight to the host. With a size of 0
glibc and the Windows runtime return NULL without setting errno or the
stream error indicator, and a negative size goes to the Windows
invalid-parameter path. FreeBSD's fgets checks n <= 0 before reading:
it sets __SERR on the stream, sets errno to EINVAL and returns NULL,
leaving the buffer and the file position untouched.

fgets_nid_postfix now does the same before calling the host. The
FileStream flag it uses was only set for encoding errors so far and is
renamed from SetEncodingError/encodingError to SetError/guestError; it
already stays set until clearerr like __SERR.

guest_standard_streams checks sizes 0, -1 and INT_MIN (NULL, errno 22,
error indicator set and cleared by clearerr, buffer and position
untouched) and that a following read still returns the line; it fails
without the change.

Fixes #3084

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:49:43 +00:00
MrMha 2eed99e770 fix(relinker): validate ELF section tables and file mappings 2026-10-11 17:47:50 +04:00
jweidenh 07297a54aa test(agc): verify rejected resource sets release storage images 2026-10-11 16:44:45 +03:00
XairRrR eba67d4130 fix(agc): render a slice of a 2D array color target into that layer of the array
A color view of slice N of a 2D array (CB_COLOR_VIEW SLICE_START, with
CB_COLOR_ATTRIB3 MIP0_DEPTH as the last slice) was rendered as a 2D
surface at the slice's address. The swizzle equations of the XOR tile
modes take the slice index (the detiler's slice bits), so the texels of
slice N of an array are not where a 2D surface at that address puts
them: a title that renders into array slices and then samples the array
read them scrambled.

The decoded target now keeps the array's address, its last slice and the
view's slice. A resident target that is a slice of an array attaches
that layer of the array's storage image, so the texels follow the
array's layout; storage images of 2D arrays are color attachments for
this, and an attachment view selects a layer. A slice whose array has
DCC, CMASK or an attachment proxy has no resident array image, and a
non-resident slice of an XOR-tiled array now throws instead of being
written in the 2D layout.
2026-10-11 15:44:20 +02:00
pushkarreddyy c3db0b0d15 perf(libSceAgcDriver): cap draw input snapshot allocation size
In #3338, Ratchet & Clank: Rift Apart (PPSA01474) hits a 36 GB / 5 s
memcpy stall at frame ~380 right after intro logos because the GPU
worker thread is blocked copying multi-gigabyte storage buffers on every
draw snapshot miss (specifically a 3.01 GiB streaming range
0x118f800000+0xbc200000 and a 232 MiB range 0x1171258040+0xe7fffc0
across 130,000 draws).

ShaderResources::PrepareDrawBindings now caps both per-allocation and
cumulative draw input buffer snapshot copies at 64 MiB by default,
overridable via APS5_DRAW_SNAPSHOT_MAX_MIB. Inputs exceeding the threshold
skip snapshotting and bind directly in place, preventing multi-gigabyte
memory copies while preserving standard small uniforms and draw arguments.
Budget allocation prioritises earlier descriptor bindings in deterministic
pipeline layout order.

Adds drawSnapshotCapTests in core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
verifying individual and cumulative capping, cross-platform cache behavior on
watched and compared hosts, and direct observation of subsequent CPU writes
on in-place bound ranges exceeding the cap. Exercised via --draw-snapshot-cap-only
registered as agc_draw_snapshot_cap in libSceAgcDriver/CMakeLists.txt.
2026-10-11 19:11:56 +05:30
DariusHQ 6ef110af48 feat(libc): implement wcstok
PS5MC (PPSA99420) stops at start-up on wcstok once sendfile is in. It
follows FreeBSD's three-argument wcstok over the guest's 16-bit wchar_t:
leading delimiters are skipped, the token ends at the next delimiter,
which is overwritten with 0, and *last is set to null when the string
runs out.
2026-10-11 16:41:50 +03:00
Lexroid 32a3047b5d fix(libkernel): run APR buffers past an unsatisfied wait on their own queue
sceKernelAprSubmitCommandBuffer ran the whole buffer on the submitting
thread, so a WaitOnAddress or WaitOnCounter that the submitter itself
satisfies after the submit returned never returned. A buffer now runs on
the submitting thread until such a wait; the rest of it, and every APR or
AMM buffer submitted after it, runs in order on one APR thread.
sceKernelAprWaitCommandBuffer and sceAmprAmmWaitCommandBufferCompletion
wait for that completion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wu3nuU87RJwjkkmxqft3sD
2026-10-11 16:37:25 +03:00
Josip Parlov 93f5220d11 refactor(audioin): name X+4jdIS75P0 sceAudioInIsPadEmbeddedMic 2026-10-11 15:36:25 +02:00
Simon 69e3c1d115 fix(libSceNpTrophy2): accept a null details or data in GetTrophyInfo and GetGroupInfo
sceNpTrophy2GetTrophyInfo and sceNpTrophy2GetGroupInfo rejected a call
unless both outputs were given, although both already fill each output
only when it is not null. PPSA18391 (Clickteam Fusion) queries trophies
with a null details. Only a call with neither output is rejected now, as
in sceNpTrophy2GetGameInfo.
2026-10-11 15:35:56 +02:00
marshmll 3d83999350 fix(build): require an SDL audio backend on Linux
The bundled SDL builds its PipeWire, PulseAudio and ALSA drivers only
when their development files are found, and otherwise keeps just the
silent dummy and disk drivers without an error. The Linux CI and
release jobs install none of them, so the v0.1.1 Linux libraries
(libSceAudioOut, libSceAgcDriver, libfmod) contain no audible driver.

Fail configuration on Linux when SDL found none of the three, install
the Debian development packages in the Linux build and release jobs,
and list the packages in the build instructions.
2026-10-11 10:34:29 -03:00
Josip Parlov 265c982eaa refactor(agc): name zARR5aCmkoY sceAgcDcbAtomicGds_0900 2026-10-11 15:33:55 +02:00
MarcZX100 afcaf91019 test(agc): cover hand-built VGPR register offset 2026-10-11 13:32:20 +00:00
Hannah Lyons 81e3e34637 test(libScePosixForWebKit): pin fnmatch bracket class syntax to FreeBSD 11 2026-10-11 09:31:23 -04:00
lorkydey 1fc9b4d93f feat(libkernel): query real-time alarms with getitimer 2026-10-11 15:30:33 +02:00
EdouardSence 95a92f35e1 feat(libSceJson2): add sce::Json::Parser::parse with a read callback
PPSA04540 (Rise of the Ronin) imports it. The characters the callback
returns are parsed as by the (text, size) overload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:28:58 +02:00
Adelmo Junior 5334bd178c fix(libSceHttp): retain authority delimiter for partial URI builds 2026-10-11 10:28:39 -03:00
EdouardSence 3faaa4b8f0 feat(libSceJson2): add the sce::Json::Array copy constructor, clear, front and iterator::operator->
PPSA04540 (Rise of the Ronin) imports all four.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:28:30 +02:00
ducloc080202 ae07d4a7a1 fix(libc): quote the executable path in the throw-site test 2026-10-11 20:25:42 +07:00
ivica00 9b439b30e9 feat(libc): implement __powisf2
PPSA02456's FMOD plugin imports this float integer-power helper, which libc does not export.
2026-10-11 15:25:25 +02:00
JAB-dev 61a9f5dc14 feat(agc): render 1_5_5_5 UNORM color targets
CB_COLOR_INFO format 17 with UNORM and the standard component swap renders
into VK_FORMAT_A1R5G5B5_UNORM_PACK16, whose attachment and blend support
Vulkan requires. AMD keeps X in the low bits and Vulkan keeps R in the
high bits, so the exports are mapped with X and Z exchanged and the stored
bits follow the guest layout. PPSA06699 renders into this format.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 15:21:46 +02:00
Sanjaysrinivas 1fe527bbec fix(agc): route registered NGG workgroups
Defer registered NGG workgroup preparation until routing is known. Share the routing decision with static ABI resolution and draws. Gate the wave64 fixture on supported mesh subgroups; retain device-independent routing coverage.
2026-10-11 15:20:24 +02:00
DariusHQ bad19037a6 feat(libkernel): implement sendfile
PS5MC (PPSA99420) stops at start-up on sendfile. It follows FreeBSD 11:
headers, the file range and trailers go to a connected stream socket, the
file offset does not move, a non-blocking socket fails with EAGAIN after
a partial send, and *sbytes reports what was sent. The checks and the
point where *sbytes is written follow kern_sendfile.c.
2026-10-11 16:19:13 +03:00
DariusHQ b9fc448343 fix(libc): format positional arguments on Windows
The guest formatter threw on %n$ and *m$, which FreeBSD's vfprintf and
glibc accept. It now reads the arguments a numbered format names into a
table first, with the types their conversions give them, and follows
FreeBSD's rules for unnumbered conversions and unnamed arguments.
2026-10-11 16:19:13 +03:00
DariusHQ d9fe7ee614 fix(libc): accept the ' flag in Windows formatting
FreeBSD's vfprintf takes ' as the thousands-grouping flag. The Windows
formatter threw on it as an unsupported conversion. The guest's setlocale
only accepts the C locale, which has no thousands separator, so the flag
changes nothing: it is dropped before the host's printf sees it, and the
host's locale cannot add separators.
2026-10-11 16:19:12 +03:00
DariusHQ b1fe54e331 fix(libc): print 0 for %#.0o of zero on Windows
C and FreeBSD's vfprintf print a single 0 when # meets octal zero with a
precision of 0. The Windows formatter passed the conversion to the host's
printf, which printed nothing; it now asks for one digit instead.
2026-10-11 16:19:12 +03:00
David 88cd5bbde5 fix(libSceAgc): accept a hand-built GE_USER_VGPR register offset in sceAgcCreatePrimState
EVO Player (PPSA99039), Jelly5 (PPSA99505), Emby5 (PPSA99515) and
Nuvio PS5 (PPSA99997) stop on main 0f863c10 with

  what():  sceAgcCreatePrimState: invalid user configuration register offsets

All four build their shader headers by hand (EVO-PLAYER-PS5
evo_agc_shader_header.c, ported from ps5-xash3d-halflife) and store the
ge_user_vgpr_en special at 0x25c (GE_USER_VGPR1, value 0) instead of
0x262 (GE_USER_VGPR_EN), as analysed in #3457. They run on the console.

OpenAGC's reconstruction of the FW 5.50 sceAgcCreatePrimState
(src/game_compat.c at 3c7e8072) copies the four special register pairs
verbatim without checking their offsets; KytyPS5's offset checks
(src/libs/agc.cpp at 16a7fe68) are EXIT_NOT_IMPLEMENTED guards. The
special is now copied at the offset the header stores, not moved to
0x262; the driver reads neither register. GE_CNTL, VGT_SHADER_STAGES_EN
and a used VGT_GS_OUT_PRIM_TYPE are still required at their own
offsets because the driver reads them there, and the error now names
the special and the offset found.

With the change all four titles get past sceAgcCreatePrimState and stop
in the shader recompiler (GetImageResource dword 3 is not a valid
runtime value), as #3457 reported for EVO Player.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit aeaa5080d9595305aa73e74d966f989c88b79839)
2026-10-11 13:19:03 +00:00
David 6db0a4df7c fix(libkernel): sync read-only and directory descriptors on Windows
FreeBSD's fsync and fdatasync succeed on a descriptor opened read-only and on a directory. _commit needs write access, so both returned EBADF there. A read-only descriptor is now flushed through a write handle from ReOpenFile and a directory through a handle opened for it, as sceKernelSync already does.
2026-10-11 15:15:00 +02:00
Mouad-Scriptz-0 b63996f1ff fix(agc): read a merged program's vertex tables past its hidden user words
A merged (NGG geometry path) program's user data starts with eight
hidden words, so the vertex buffer and attribute table offsets of its
AGC header, which count from the first user SGPR, were read eight words
too early and found zeros. Killzone: Liberation (PPSA11142) stopped on
`AGC graphics: null vertex buffer table address` at the first frame of
its PSP game. The decoder now adds the hidden word count to the table
reads; the registers reported to the recompiler are unchanged, as it
already maps them from the first user SGPR. `agc_driver_graphics` gains
a merged and a plain layout case.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 13:13:01 +00:00
David 9c7aa0d61a feat(libc): implement ftrylockfile
Porpoise PPSA99764 stops after pthread_attr_* (#3494) with the
predicted `FAIL: unresolved ELF import h05OHOMZNMw from
libSceLibcInternal.prx` (idx 311, call site 0x8EC37); RetroArch
PPSA99169 imports it at idx 448 (call site 0xA4A27). h05OHOMZNMw is
ftrylockfile by tools/nid_names.py and aerolib.csv (zecoxao/sce_symbols
2883963a); ps5-payload-dev/sdk f5d40f02 declares
`int ftrylockfile(FILE *)` in include/freebsd/stdio.h.

ftrylockfile tries the same host CRT stream lock that flockfile,
funlockfile and every locking host stdio call on the stream take, so
no second lock exists beside the one stdio uses. It returns 0 when the
lock is acquired or already owned by the caller (recursive, released by
as many funlockfile calls) and -1 when another thread holds it, as
FreeBSD 8c639945 lib/libc/stdio/_flock_stub.c:89-104 does. Linux calls
glibc ftrylockfile. UCRT has no try variant of _lock_file, so Windows
calls TryEnterCriticalSection on the CRITICAL_SECTION that _lock_file
enters (__crt_stdio_stream_data::_lock, ucrt/inc/corecrt_internal_stdio.h,
same layout in Windows SDK 10.0.19041, 10.0.22621 and 10.0.26100). A
null or closed stream throws. The UCRT layout dependency is recorded in
TechnicalDebt.

guest_standard_streams covers trylock on an unlocked stream, re-entry
by the owner, failure from another thread while held (also after one of
two unlocks and while another thread holds flockfile), stdio calls
from another thread blocking on the trylock-held lock, release order,
and null and closed streams.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 18:42:23 +05:30
Superhe11 83c9eb7af1 fix(agc): keep uncached storage images out of the resource cache 2026-10-11 16:12:02 +03:00
EdouardSence 295e48f059 feat(libSceNgs2): export sceNgs2ReportRegisterHandler and sceNgs2ReportUnregisterHandler
PPSA04540 (Rise of the Ronin) imports both and now loads past them;
calling either throws until NGS2 produces reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:11:24 +02:00
EdouardSence 9f3cc31f77 feat(libSceRazorCpu): add sceRazorCpuPushMarker
PPSA04540 (Rise of the Ronin) imports it. Like sceRazorCpuPushMarkerStatic
it does nothing without a capture and returns 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:09:35 +02:00
MarcZX100 a0e3d2098d fix(shader): omit sRGB variants for comparisons 2026-10-11 13:09:21 +00:00
thibaut db1f3c38ef fix(shader): drop masked selects proven unobserved through whole quad mode
A lane set contained in X is contained in WQM(X). Containment is proven
through BitwiseAnd and through ballots evaluated in the uniform entry
blocks, where every invocation is active. Under a whole quad mode mask the
masked lanes form whole quads, so implicit-LOD pixel samples, which only
read their own quad, do not observe them.

This removes the selects that kept the packed pixel ancillary input alive
after its fields were extracted in GTA V (PPSA04264) pixel shaders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-11 15:05:49 +02:00
Scramblrrrr 3943287d63 refactor(shader): drop the overlapping global loop join fallback 2026-10-11 10:00:07 -03:00
Scramblrrrr 3a80442635 fix(shader): validate conditional exits before accepting every fallback 2026-10-11 10:00:07 -03:00
Scramblrrrr b23b54a6d7 perf(shader): avoid rerouting synthetic loop-exit forwarders 2026-10-11 10:00:07 -03:00
Scramblrrrr 5781203184 test(shader): expect main to merge the shared exit tail without routing 2026-10-11 10:00:07 -03:00
Scramblrrrr 901c627862 fix(recompiler): preserve the guarded loop exit fallback before shared routing
Keep the AlxcBTW #24 fallback as a separate guarded attempt before enabling shared-exit and nested-continuation repairs. Add the reduced padded shader reported by orishamir on #2523 as an end-to-end regression; the abstract graph does not reproduce the same failure.
2026-10-11 10:00:07 -03:00
Scramblrrrr b0c86ec07f fix(recompiler): privatize shared continuations before loop gateways 2026-10-11 10:00:07 -03:00
Scramblrrrr e6c8e1e9c7 fix(recompiler): route shared loop exit selections in the guarded fallback 2026-10-11 10:00:07 -03:00
AlxcBTW 4df387d0c1 fix(recompiler): reject a loop-exit pass result that is not structured
The third structurize pass, which routes loop exits that leave the loop
before they meet, runs only when the plain and the privatized pass
throw, and its result was used without a check. Merged with #2471, it
turns some of those budget failures into graphs that spirv-val
rejects. In this one, selection 12 of the result lies in the selection
at 7 and branches to 7's merge block 13:

  {{1}, {2, 3}, {4}, {5}, {6, 7}, {}, {8, 9}, {10, 11}, {1}, {12, 4},
   {5}, {13}, {8, 14}, {15, 16}, {7}, {13}, {4}}

  block 12 exits the selection headed by block 12, but not via a
  structured exit

hasStructuredConstructs checks the third pass's result against the
structured control-flow rules of the SPIR-V specification (2.11), with
dominance and post-dominance taken over branch, merge and continue
edges. Back edges come only from a loop's continue block. A conditional
without a merge breaks or continues its innermost loop. A header
strictly dominates its merge, and a loop header its continue block. A
construct contains the merge of every header inside it and is entered
only through its header. It is left only to its own merge or to the
innermost loop's merge or continue block, and a continue construct only
to its loop's header or merge. When the result fails, the second pass's
error is reported, as when the third pass throws. The first two passes
are unchanged.

Differential fuzz with the structured-program generator and random
reducible graphs. Oracle: exact post-dominators,
requireStructuredBranches, merges dominated by their headers, the
original's executions, and spirv-val (SPIRV-Tools v2026.4).
- Against 9fa7d06a: the same outcome and output on every graph. That
  covers 100,000 random graphs at 0 words and with one block at 1000,
  and 30,000 programs at 16 and at 1000 words per block, each also with
  one block at 1000.
- Merged with #2471, the same 30,000 programs: the third pass had made
  41, 42 and 45 of them invalid (16 words, 16 with one block at 1000,
  1000 words). These end in #2471's own error again, and nothing else
  changes. The 1, 1 and 18 graphs that d59a9167 merged with #2471
  already structures invalidly come from the first two passes and stay
  as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:00:06 -03:00
AlxcBTW 6500daa012 fix(recompiler): route loop exits that leave the loop before they meet
A loop whose exit paths leave the loop construct before they meet got
the nearest common post-dominator of its exits as merge, and
splitSharedMergeBlocks never separated it. An exit continues the
enclosing loop, so its path to that merge runs through the outer
header again, or an exit enters a block that a branch before the loop
also reaches. splitOneLoopMerge gave the loop a forwarding merge block
each round, the other path still bypassed it, and the post-dominator
stayed the same block until "CFG shared merge splitting exceeded
budget". These shapes from #2642 fail that way on main, on d59a9167,
with #2471 and with both:

  {{1}, {2}, {3, 4}, {2, 5}, {}, {1}}
  {{1}, {2, 3}, {4, 5}, {}, {3, 6}, {1}, {2}}
  {{1, 3}, {2, 4}, {3, 1}, {4}, {}}
  {{1, 2}, {3, 2}, {4}, {4, 1}, {}}
  {{1, 2}, {4}, {3, 1}, {4, 2}, {}}

When the plain and the privatized pass both fail, Structurize now runs
a third pass. It routes such a loop's exits through one junction with
routeLoopExits, as loops whose exits have no common post-dominator are
routed already, and gives an outer loop whose only latch lies in an
inner loop its own continue block. In that pass a loop exit conditional
that is neither a direct break or continue nor has an exit tail of its
own is structured as a selection, and an exit tail that the other arm
reaches is not used as one. Without that, graphs the routing unblocks
keep a conditional without merge (the rule from #2762) or a selection
entered past its header. Graphs that the first two passes structure
are unchanged, and when the third pass fails too, the second pass's
error is reported.

Differential fuzz against main, reducible graphs with 5 to 9 blocks,
each with 0 estimated words per block and again with one block at 1000
words (the privatizeSharedReturns path). Oracle: exact post-dominators,
requireStructuredBranches, merges dominated by their headers, the same
executions as the original graph, and spirv-val (SPIRV-Tools v2026.4,
Vulkan 1.3) on a module emitted from the structured graph.

- 200,000 random graphs. main structures 178,743 (0 words) and 178,750
  (1000 words); the output is identical on all of them. Of main's
  14,256 and 14,311 budget failures 13,527 and 13,596 now structure,
  and 2,576 and 2,565 of its refusals. No new output is invalid. The
  invalid outputs are main's 530, plus at 1000 words one graph that
  d59a9167 already turns from a budget failure into a back edge to a
  block that is not a loop header.
- 24,000 structured programs from orishamir/anyps5-cfgfuzz's
  generator (if/else, loops, break, continue, return). main structures
  21,093 and 21,022; the output is identical. 619 of 2,448 and 634 of
  2,429 budget failures now structure. No new output is invalid; the
  invalid outputs are main's 92.

agc_structurizer has the five shapes; requireOriginalBranches now
follows route variables. agc_shader_control_flow has two RDNA programs
of the first two shapes. The non-GPU tests and the 253 agc_driver GPU
tests pass on Windows (RTX 5070 Laptop).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:00:06 -03:00
AlxcBTW 5182c031a7 fix(recompiler): merge a loop selection where its arms meet in the iteration
A selection in a loop whose arms both reach their nearest common
post-dominator within the iteration got that post-dominator as its
merge. When an arm can also continue the loop, the post-dominator
follows the back edge: the continuing path re-enters the loop header
and reaches the outer selection's merge without passing the block where
the arms meet. In the loop {1}, {2, 4}, {3, 4}, {4, 5}, {1, 6}, {1}, {}
from #2642 (latches 4 and 5) the selections at 1 and 2 both merged at 4.
splitSharedMergeBlocks gave 2 a forwarding merge block, recomputed 4 for
it because 3 continues through 5, and repeated until "CFG shared merge
splitting exceeded budget: originalBlocks=9 currentBlocks=45
splitBudget=36".

When that post-dominator is inside the loop construct, findSelectionMerge
now takes the arms' nearest common post-dominator over the paths of the
iteration that reach it, so paths that leave through the continue block
or the loop's merge no longer move the merge past the arms' join. When
no arm leaves early the result is the same block as before. The loop
structures with two forwarding blocks and no clones or route variables;
so do three latches, the selections on the false side, and an if-else
whose one arm continues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:00:06 -03:00
LeandroLP23 ce0239c940 fix(libkernel): return lseek errors for directory descriptors instead of throwing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:57 +02:00
Hussein Kadhim 6db8c81aae docs(technical-debt): describe the Windows directory snapshot lifetime exactly 2026-10-11 14:59:57 +02:00
Hussein Kadhim cb6dcbf844 fix(libkernel): keep directory lseek off the shared lock and report offset overflow
lseek on a non-directory descriptor no longer takes the directory table lock when no directory is open, and a listing is read under the descriptor's own lock. SEEK_CUR with offset 0 only reports the position, and an overflowing SEEK_CUR offset reports EOVERFLOW.
2026-10-11 14:59:57 +02:00
Hussein Kadhim 7a68e11ab4 fix(libkernel): rewind Windows directory descriptors on lseek
lseek on a directory descriptor returned 0 without moving the listing, so getdents after lseek(fd, 0, SEEK_SET) reported nothing.
2026-10-11 14:59:57 +02:00
LeandroLP23 23dad48559 docs(debt): record the RDNA2 sweep for every f16 rounding mode of v_fma_mixlo/mixhi_f16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:56 +02:00
AlxcBTW bc517d6058 fix(shader): give an exact zero mix f16 sum -0 when rounding toward -infinity
With f16 rounding toward -infinity, v_fma_mixlo_f16 and v_fma_mixhi_f16
gave +0 for an exact cancellation such as 1.0 * 1.0 + -1.0, because the
f64 sum is computed to nearest. RDNA2 gives -0 there, as IEEE 754 does
for an exact zero sum rounded toward -infinity, measured on gfx1036 in
#2631. An exact zero sum now gives -0 in that mode unless both the
product and the addend are +0. A nonzero result that rounds to zero
keeps its sign, so a tiny positive sum still gives +0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:56 +02:00
AlxcBTW f22b9fa02a fix(shader): round v_fma_mixlo_f16 and v_fma_mixhi_f16 in every f16 rounding mode
The f16 forms of v_fma_mix threw for any FLOAT_MODE with an f16 rounding
other than to nearest even. ps5-opengl's shaders run with FLOAT_MODE
0xcc, f16 rounding toward zero with f16 denormals kept, so PPSA99005
stopped at its first draw (#2631).

The exact product-sum, already computed in f64 with round to odd, is now
rounded once in the mode's direction: scaled by the f16 step at its
exponent, truncated, floored or ceiled, and scaled back. A result beyond
65504 becomes infinity or 65504 as IEEE 754 gives for the direction. On
RDNA2 (gfx1036) -1.5 * 2^-24 + 2^-126 gives 0x8002 with round toward
-infinity, and this gives the same. Flushed f16 denormals still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:55 +02:00
ducloc080202 e9736282f7 fix(libc): name the throw site in unhandled exception reports 2026-10-11 19:59:31 +07:00
XairRrR 79c8d36901 fix(agc): reject constant color factors and memory-writing stages in split SWAP_ALT blends
Review follow-up to the 8_8 SWAP_ALT blending. The second channel of
such a target holds the guest's alpha. Vulkan applies the green blend
constant to it for CONSTANT_COLOR and ONE_MINUS_CONSTANT_COLOR, where the
guest's alpha equation uses the alpha constant. Decoding now throws for
these factors on a SWAP_ALT 8_8 target, unless the equation is MIN or
MAX, which ignore factors.

The second pass of a split draw runs every stage again, not only the
pixel shader, so a vertex or geometry stage that writes memory would
write twice. The memory-write check (now ShadersWriteMemory) covers all
the draw's stages.
2026-10-11 14:58:57 +02:00
jweidenh 82c04e4027 fix(shader): keep sRGB comparisons in the emulated runtime mode
(cherry picked from commit 5377951c552f2313c8f7a52b57bd7a54c5f7fb7f)
2026-10-11 12:54:54 +00:00
XairRrR 94cffec3a7 perf(agc-driver): prepare shader ABI variants before taking the preparation lock
A shader preparation transaction took the global writers lock when it
was constructed and kept it to its end. ResolveShaderAbi, reached from
sceAgcCreateInterpolantMapping and sceAgcLinkShaders, compiled its
variants inside such a transaction, so every game thread creating or
linking shaders waited behind one compile: Uncharted's stalled frames
spent about half a second each in shader registration.

The root transaction now takes the lock on its first Read, Edit or
Hold. ResolveShaderAbi prepares the variants before reading the
prepared state when its ABI was not committed yet. Registry
publication holds the lock as before: PublishRegisteredShader holds
it, and RegisterShader holds it before the driver mutex, so the lock
order is unchanged. Commit takes no lock: a transaction with changes
already holds it.
2026-10-11 14:54:48 +02:00
lorkydey cb9932007a fix(relinker): ignore no-op executable relocations 2026-10-11 14:53:59 +02:00
Hannah Lyons bf4cb4974d feat(libScePosixForWebKit): implement fnmatch 2026-10-11 08:52:48 -04:00
hugodearaujo bdf67fcc49 feat(libs): declare the PS VR2 exports PPSA15878 imports
Propagation: Paradise Hotel (PPSA15878) does not load on main: its
executable imports 15 PS VR2 functions that no library exports, the
first reported being sceVrTracker2GetPlayAreaOrientedBoundingBox
(snYs7Nf-RKk). Declare the nine libSceHmd2 reprojection and gaze
exports, three libSceVrTracker2 exports and three scePadVrController
trigger effect exports, without parameters, as throwing stubs. Names
come from the aerolib NID list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:51:00 -03:00
hugodearaujo a61e2d35dd fix(libSceSysmodule): return INVALID_VALUE for module id 0
Measured on a PS5 (firmware 13.60): sceSysmoduleIsLoaded,
sceSysmoduleLoadModule and sceSysmoduleUnloadModule with id 0, and the
Internal and InternalWithArg calls with id 0 or 0x80000000, return
0x805A1000 and leave the WithArg result untouched. They threw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:51:00 -03:00
Hannah Lyons 0e9a8dd949 feat(libkernel): export execv 2026-10-11 08:50:20 -04:00
Adrià Franch b33d2e3736 docs(debt): record the disabled user VGPR enable alias in sceAgcCreatePrimState
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:49:38 +00:00
MarcZX100 a9575dc70b fix(agc): normalize disabled user VGPR special offset 2026-10-11 12:49:38 +00:00
Abdulrahman Elkordy 8b0b78f529 test(libkernel): don't require restoring the directory time on Windows
The empty-path utimes check restores the working directory's write time
afterwards and requires the restore to succeed. With MinGW,
std::filesystem::last_write_time fails with EACCES when setting a
directory's time (a file's works), so guest_filesystem aborts there on
Windows. The restore stays, only its result is no longer checked.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 15:49:25 +03:00
MarcZX100 9e8b5a21bc fix(shader): allow constant-zero sRGB comparisons 2026-10-11 12:49:23 +00:00
ArjenS-LA 859736aa0e fix(net): preserve truncated UDP receives on Windows 2026-10-11 09:48:50 -03:00
MarcZX100 b316c9885d fix(libc): resume host foreign exceptions with host unwinder 2026-10-11 12:48:47 +00:00
MarcZX100 5550ca63dd fix(agc): wait for shutdown at shader ABI entrypoints 2026-10-11 12:48:40 +00:00
Hussein Kadhim d4301cf9b3 fix(libkernel): parse and print inet text addresses by the guest rules
inet_pton and inet_ntop no longer call the host resolver library, whose
accepted forms and output differ from the guest's (leading zeros,
zone ids, IPv4-embedded printing).

(cherry picked from commit 058d808ae7c43042d0ffd5fad76062a2df16b871)
2026-10-11 12:46:21 +00:00
pushkarreddyy 06f84010bb feat(libc): implement reallocf
Two catalog titles stop on the absent libSceLibcInternal export reallocf
(YMZO9ChZb0E) on main 0f863c10:

- PPSA97510 PSXS5 2.2.0
- PPSA98510 SwanStationPS5 1.1.3

    FAIL: unresolved ELF import YMZO9ChZb0E from libSceLibcInternal.prx

reallocf follows FreeBSD 11 lib/libc/stdlib/reallocf.c (freebsd-src
stable/11 5ed7eb0d97ba4436218e810f61bd059acba984c2) on top of the guest
realloc: it reallocates through the application heap, and when realloc
fails (the application allocator returns null or the default heap
rejects the size) it frees the block through the same allocator, sets
ENOMEM and returns null. Size 0 frees and returns null as realloc does
here, so the block is not freed twice. Other heap failures throw, as
for realloc. The NID matches tools/nid_names.py and aerolib.

The application heap tests cover grow, shrink, a null pointer, size 0
and failure with both the replacement and the default allocator.

Co-Authored-By: screamm <noreply@github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 18:16:07 +05:30
Mouad a553e22638 feat(agc): write memory for WRITE_DATA with DST_SEL 3
Killzone: Liberation (PPSA11142) writes its frame fence with
`sceAgcDcbWriteData(dst 6, cache policy 3, write confirm)`, which the
SPRX-confirmed encoding turns into WRITE_DATA with DST_SEL 3 and a label
address in the title's memory that RELEASE_MEM and WAIT_REG_MEM then
use. The validator rejected DST_SEL 3 as the GDS; it now writes guest
memory like DST_SEL 5, resolves as a label, and the title runs past its
first frame. TechnicalDebt records where the semantics come from.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 9c53b7f6e8ce2ca81d8f0fa551d12632acfeb60d)
2026-10-11 12:45:26 +00:00
Adrià a11c8f7f70
Merge pull request #3511 from krishalivaibhav/codex/fix-imgui-submodule-config
build: remove accidental imgui gitlink
2026-10-11 14:42:34 +02:00
BharatYadav007 8355b1f7b8 feat(libc): implement setlogmask 2026-10-11 18:07:14 +05:30
Hannah Lyons 6aa0b4fb22 fix(libkernel_sys): create symlinks with CreateSymbolicLinkW on Windows 2026-10-11 08:31:59 -04:00
krishalivaibhav fab9f576ae build: remove accidental imgui gitlink 2026-10-11 17:51:09 +05:30
Adrià 1e8fff68c8
Merge pull request #3481 from sypher69/fix/fchdir-search-permission
fix(libkernel_sys): check fchdir search permission on Linux
2026-10-11 14:09:47 +02:00
Winvoker c9038f7d8d fix(progress): match stub calls across whitespace 2026-10-11 15:06:06 +03:00
Adrià 2220effbe4
Merge pull request #3482 from MarcZX100/codex/rx-cross-block-3475
fix(agc): retain cross-block R_X coordinate XORs
2026-10-11 14:02:02 +02:00
Adrià 8b679d8d9e
Merge pull request #3498 from MarcZX100/codex/progress-inert-reporting
feat(tools): mark behaviourally empty functions in progress reports
2026-10-11 13:59:56 +02:00
Adrià 03708282b3
Merge pull request #3495 from Lorkydey/fix/relinker-registry-input-preservation
fix(relinker): preserve input binaries when writing registries
2026-10-11 13:56:53 +02:00
Adrià c253de1165
Merge pull request #3428 from MarcZX100/codex/fix-libkernel-open-empty-path-3308
fix(libkernel): reject empty sceKernelOpen paths
2026-10-11 13:55:48 +02:00
Adrià e783f19bc1
Merge pull request #3441 from MarcZX100/codex/fold-unordered-infinity-compares-3355
fix(recompiler): fold true unordered comparisons against f32 infinity
2026-10-11 13:55:17 +02:00
Adrià a5d75aa24e
Merge pull request #3490 from MarcZX100/codex/image-dimension-boundary-3460
test(agc): remove ambiguous 1D V wrap expectation
2026-10-11 13:54:57 +02:00
Adrià 7d7df0560e
Merge pull request #3491 from babyhuey/feat/libkernel-sys-symlink
feat(libkernel_sys): implement symlink
2026-10-11 13:54:51 +02:00
Adrià 6c4a84fbc6
Merge pull request #3492 from fable-void/pr/macos-module-start-args
fix(relinker): pass module start arguments to macOS guest initializers
2026-10-11 13:54:49 +02:00
Adrià eaffdc402f
Merge pull request #3489 from MarcZX100/codex/carry-equeue-level-once-3115
fix(libkernel): report level-triggered equeue events once per wait
2026-10-11 13:54:44 +02:00
Adrià bc193544f4
Merge pull request #3487 from DariusHQ/feat/libkernel-underscore-ioctl
feat(libkernel): export _ioctl
2026-10-11 13:54:41 +02:00
Adrià 84f43dcdac
Merge pull request #3486 from MarcZX100/codex/carry-sigsetjmp-3432
feat(libkernel): implement sigsetjmp
2026-10-11 13:53:51 +02:00
Adrià fd1a66cab6
Merge pull request #3484 from AchrafReyani/feat/libkernel-pthread-mutexattr-gettype
feat(libkernel): implement pthread_mutexattr_gettype
2026-10-11 13:53:23 +02:00
Adrià 2e2c531441
Merge pull request #2258 from krishalivaibhav/codex/spirv13-image-regression
test(shader): cover SPIR-V 1.3 image compilation without a GPU
2026-10-11 13:53:14 +02:00
Adrià c5a304a824
Merge pull request #3478 from fable-void/pr/macos-write-watch-remap
fix(libc): watch direct memory mapped over its reservation on macOS
2026-10-11 13:52:58 +02:00
Adrià c68b887799
Merge pull request #3479 from MarcZX100/codex/carry-arc4random-3450
feat(libScePosixForWebKit): implement arc4random
2026-10-11 13:52:52 +02:00
Adrià 673d1e65ca
Merge pull request #3476 from alfalfa-star/carry/select-non-socket-descriptors
fix(libkernel): answer select on the standard and random device descriptors
2026-10-11 13:52:21 +02:00
Adrià 6f7a12b0ee
Merge pull request #3472 from oneandonlydean/up4/fix-bda-note-write-nvidia-hang
fix(shader): set a BDA-written page's bit inside the slot probe loop
2026-10-11 13:51:42 +02:00
Adrià 23f274e785
Merge pull request #3467 from MarcZX100/codex/rudp-context-queries-3073
feat(libSceRudp): report disconnected context queue state
2026-10-11 13:51:11 +02:00
Adrià 6731a610e7
Merge pull request #3470 from Techx3/trophy2-show-trophy-list
fix(libSceNpTrophy2): return success from sceNpTrophy2ShowTrophyList
2026-10-11 13:51:05 +02:00
Adrià 712ae61a02
Merge pull request #3465 from MarcZX100/codex/fix-empty-kernel-paths-3308
fix(libkernel): reject empty filesystem paths
2026-10-11 13:50:57 +02:00
Adrià 544b38d094
Merge pull request #3474 from 014-code/fix/agc-resource-cache-storage-eviction
fix(agc): evict resource-cache images with storage entries
2026-10-11 13:50:49 +02:00
Adrià daa13905cb
Merge pull request #3434 from Yuva1024/fix/agc-nvidia-pipeline-link-optimization
fix(agc): skip the background pipeline relink on NVIDIA's proprietary driver
2026-10-11 13:49:43 +02:00
Adrià 6fd350f075
Merge pull request #3464 from GustavoGamarra95/test/agc-a2c-normalized-exports
test(agc): cover UNORM16 and SNORM16 exports with alpha-to-coverage
2026-10-11 13:49:40 +02:00
MarcZX100 8a390b06df fix(agc): XOR overlapping R_X coordinate contributions 2026-10-11 11:49:23 +00:00
Adrià b33b1b8e66
Merge pull request #3458 from alfalfa-star/fix/agc-dcc-writeback-keys-reused
fix(agc): store a storage image's DCC keys at write-back only when not stored yet
2026-10-11 13:49:15 +02:00
Adrià 3a37a896fa
Merge pull request #3455 from YossiYad/carry/select-non-socket-descriptors
fix(libkernel): answer select on non-socket descriptors
2026-10-11 13:49:06 +02:00
jweidenh 6199661506 test(recompiler): verify BDA store boundary faults and written pages 2026-10-11 07:46:41 -04:00
Adrià 08e0079e4d
Merge pull request #3451 from LeandroLP23/fix/libc-time-strftime-freebsd-conversions
fix(libc): format %k, %l, %s, %v and %+ in strftime
2026-10-11 13:46:24 +02:00
Adrià e38b5e95d2
Merge pull request #3300 from lendinglibrary/fix/3212-dispatch-split
fix(agc): split a compute dispatch over the workgroup count limit
2026-10-11 13:46:20 +02:00
Adrià cafc074e1a
Merge pull request #3454 from GustavoGamarra95/refactor/share-procmap-query
refactor(agc): share the PROCMAP_QUERY lookup with GuestMemory
2026-10-11 13:45:42 +02:00
Adrià 7ff417f8b9
Merge pull request #3449 from hypermoist/feat/np-entitlement-game-trials-flag
feat(libSceNpEntitlementAccess): declare sceNpEntitlementAccessGetGameTrialsFlag
2026-10-11 13:45:07 +02:00
Adrià 8f47444853
Merge pull request #3446 from MarcZX100/codex/tolerate-process-time-clock-skew-3422
test(libkernel): tolerate process-time clock skew
2026-10-11 13:45:05 +02:00
Adrià 83929de897
Merge pull request #3444 from Pipodi/fix/fused-hull-header
fix(agc): select the registered back half for a fused hull header
2026-10-11 13:44:59 +02:00
Adrià 612e93651c
Merge pull request #3453 from LeandroLP23/fix/libc-scanf-suppressed-eof
fix(libc): return 0 from scanf when input fails after a suppressed conversion on Windows
2026-10-11 13:44:57 +02:00
Adrià 97fbc7e629
Merge pull request #3447 from sypher69/fix/thread-process-affinity-inheritance
fix(libkernel): inherit process affinity in new guest threads
2026-10-11 13:44:45 +02:00
MarcZX100 05504bb05e fix(tools): retain literals when classifying inert returns 2026-10-11 11:44:32 +00:00
Leandro Soares 90a82da283 feat(tools): mark behaviourally empty bodies in the progress report
Cherry-picked from commit f1be92e95c02be451971fc1a8eec139e738e936d.
2026-10-11 11:44:28 +00:00
Adrià 077eeb05ea
Merge pull request #3448 from Feuris/carry/agc-debug-raise-exception
feat(libSceAgc): implement sceAgcDebugRaiseException
2026-10-11 13:43:54 +02:00
notaxeltv ae425ed920 feat(libSceTextToSpeech2): return EOPNOTSUPP from remaining speech exports
Titles that call Open/Speak after a failed initialize should get the same unavailable-engine error instead of a throw.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 13:43:46 +02:00
Adrià e5d4f59dac
Merge pull request #3438 from ivica00/fix/srgb-bilinear-cube-compare
fix(shader): return 0 for 8-bit sRGB color comparison
2026-10-11 13:43:27 +02:00
Adrià ea31cff19c
Merge pull request #3436 from MarcZX100/codex/rmdir-dot-einval-3116
fix(filesystem): reject final dot removal paths
2026-10-11 13:42:56 +02:00
Adrià 22b1782e01
Merge pull request #3442 from babyhuey/feat/libkernel-pthread-getthreadid-np
feat(libkernel): implement pthread_getthreadid_np
2026-10-11 13:42:48 +02:00
David dce174749d feat(libSceAmpr): implement _Cnd_signal and _Cnd_init_with_name
Deathloop (PPSA01670), Minecraft Legends (PPSA05510) and GTA III
Definitive Edition import both from libSceAmpr. They take a pointer to
the handle slot and act on the conditions created by the libc _Cnd_init:
_Cnd_signal wakes one waiter through a libc helper, _Cnd_init_with_name
is _Cnd_init with the name ignored. _Thrd_id still throws.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 13:41:49 +02:00
lorkydey 0cfdc79e59 fix(relinker): preserve input binaries when writing registries 2026-10-11 13:38:27 +02:00
MarcZX100 668a6db50d test(agc): avoid ambiguous row-boundary filtering 2026-10-11 11:34:47 +00:00
Hannah Lyons 6bc537ce01 feat(libkernel_sys): implement symlink 2026-10-11 07:31:49 -04:00
Hussein Kadhim 59517ef5f5 test(libkernel): cover blocking wait, edge and repeated AMPR equeue events
Document the level-triggered user event semantics of sceKernelWaitEqueue in TechnicalDebt.

(cherry picked from commit db79bee1e597effff34c72493ed893d4e750b95d)
2026-10-11 11:28:34 +00:00
Hussein Kadhim a9b7b20f8f fix(libkernel): report a level-triggered equeue event once per wait
A user event added with sceKernelAddUserEvent stays triggered until it is
deleted. The collection loop kept re-emitting it until the caller's event
buffer was full, so a wait with num > 1 returned the same event num times.
Like kevent, each event is now reported at most once per call; distinct
queued completions of one event are still delivered in order.

(cherry picked from commit db28ebbb7f078cb593cf6b7bb34b8db49dd94630)
2026-10-11 11:28:34 +00:00
AlxcBTW 66236674f0 fix(recompiler): keep lane 31 a shuffle without subgroup arithmetic
The half-wave scan rules for 32-lane hosts made lane 31 of a matched
scan a subgroup reduction and threw on a device without subgroup
arithmetic, where the read used to build as a shuffle of the scan. Such
a device now keeps the shuffle for lane 31; lane 63 still reads the
identity, which needs no arithmetic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:24:14 +02:00
AlxcBTW 98ce96a8b9 test(agc): run a wave64 NGG full-wave OR on a 32-lane device
A wave64 vertex program with the culling scan of #2783 (lane < s3's
primitive count, row_shr bound_ctrl:1 OR scan, v_permlanex16_b32,
v_readlane_b32 of lanes 31 and 63) compares the wave OR with the ballot
of its keys and collapses its triangle when they differ. On a 32-lane
device every pixel of the grid must be covered.

Before the s3 change the program does not build on 32 lanes; with a
shuffle from lane 31 instead of the subgroup reduction no pixel is
covered, as the device leaves lanes of each vertex warp idle. Other
subgroup widths skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:24:14 +02:00
AlxcBTW 24894376ab fix(recompiler): give wave64 vertex programs on 32-lane hosts a 32-lane s3
A wave64 vertex program runs at one guest lane per invocation, so on a
32-lane host subgroup its lanes 32-63 have no invocation. The vertex
entry still set s3 = 64 | 64 << 8, telling the program that its wave
holds 64 vertices and 64 primitives. An NGG culling program then keys a
full-wave OR on lane < s3's primitive count, lanes 32-63 hold real cull
results, and its v_readlane_b32 of lane 63 cannot be built (#2783).

The entry now sets s3 = 32 | 32 << 8 for a wave64 program on a 32-lane
host, the wave the host runs; the console launches waves with fewer
vertices and primitives. The host subgroup width reaches the vertex
input the way it reaches the compute and mesh inputs
(BuildShaderStageInputInfo from HostSubgroupSize), and the source,
prepared-shader and disk cache keys already carry it for every stage.
Programs that do not read s3 are unchanged; wave32 programs and other
host widths keep the full wave.

The keys are then 0 in lanes 32-63, so the read is sound. On a 32-lane
host, when the existing half-wave scan rules fail, the scan may also:
- run under s_mov_b64 exec, -1 (EXEC constant true);
- use bound_ctrl:1 row_shr steps when 0, the fill, is the identity (OR,
  add, unsigned max), also into another register, whose old value never
  shows since such a step writes every lane;
- take keys shown to be 0 in lanes 32-63: built from 0 through selects
  under a lane id or v_mbcnt of -1 below at most 32, v_cmp_ne_u32 against
  0, ORs, DPP and permlanes, in stages whose entry EXEC is every lane.
Lane 63 is then the identity and lane 31 the subgroup reduction of the
host's invocations. A shuffle from lane 31 is not enough: an RTX 5070
runs the vertex warps of a non-indexed triangle list with 30 of their 32
invocations. A v_readlane_b32 outside the host subgroup of another value
that is 0 in lanes 32-63 reads 0. Only reads that used to throw change,
besides lane 31 of such scans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:24:14 +02:00
MarcZX100 a6cb65e481 fix(agc): retain cross-block R_X coordinate XORs 2026-10-11 11:23:47 +00:00
David b79c8e2143 feat(libkernel): implement sigsetjmp
XPSemu (PPSA97358) stops next at sigsetjmp (aRo9AhFUXcM) from libkernel,
per the body of #3323 "feat(libkernel): implement cpuset_setaffinity for
the calling thread or process": "XPSemu: with this PR, the next stop is
`sigsetjmp` (`aRo9AhFUXcM`)". RetroArch and PS5MC list it under libkernel
in the absent-import tables of #1578; aerolib names aRo9AhFUXcM sigsetjmp.

sigsetjmp is FreeBSD's amd64 sigsetjmp (lib/libc/amd64/gen/sigsetjmp.S,
release/11.4.0 8c639945), the counterpart of the merged siglongjmp (#2935)
and its sigjmp_buf layout (sys/x86/include/setjmp.h, _JBLEN 12): it stores
savemask at offset 88 and, when it is nonzero, saves the current mask at 72
through _sigprocmask(SIG_BLOCK, NULL, oset); then it records the return
address, rbx, rsp, rbp, r12-r15 and the x87 control word, and returns 0.

guest_signal_sets now jumps through the export instead of its copy of
FreeBSD's sigsetjmp, and checks that savemask 0 leaves the mask slot
untouched, a nonzero savemask records the current mask and its own value,
and the callee-saved registers come back after siglongjmp.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 8a609a5a1f189dce107a871e7da0fd55c746921f)
2026-10-11 11:23:10 +00:00
fablevoid 1b865fc3ea fix(relinker): pass module start arguments to macOS guest initializers
The macOS image initializer called a guest module's DT_INIT with no
arguments, so a module started with sceKernelLoadStartModule never saw
its args and argp, and its result was dropped. The Linux writer already
calls DT_INIT through libkernel's pending argument handoff. On the
macOS port, the PSN plugin of PPSA12544 refuses to start without its
argument block ("PSN is an old version that cannot be used by the
current player runtime") and the title then crashes.

A guest module with DT_INIT now gets two slots bound to
__aps5_get_pending_module_args_nid_no_patch and
__aps5_set_module_init_result_nid_no_patch, and its initializer calls
DT_INIT with the args and argp that sceKernelLoadStartModule records,
as on Linux, then hands the result back. The TechnicalDebt sentence
about the missing arguments on macOS is removed.

guest_module_args also relinks its fixture with --macos and checks the
two binds; on x86-64 macOS it loads the module and checks that DT_INIT
receives the arguments and that its result is returned.

AI-assisted: yes
2026-10-11 11:22:38 +00:00
DariusHQ b4a59e34c4 feat(libkernel): export _ioctl
Stremio Plus (PPSA74126) stops at start-up on _ioctl, which its statically
linked tc* functions call. FreeBSD's _ioctl is the same system call as
ioctl, so it forwards to ioctl.
2026-10-11 14:19:02 +03:00
Dani 0e4d94ce39 fix(libkernel_sys): check fchdir search permission on Linux 2026-10-11 13:18:30 +02:00
David 7083b2941a feat(libScePosixForWebKit): implement arc4random
Implement arc4random (UISQ-dQzw28) in libScePosixForWebKit on top of the
existing arc4random_buf, so both draw from the same thread-local host
std::random_device. Like FreeBSD 11.4 lib/libc/gen/arc4random.c
(8c639945) it returns a uniformly distributed 32-bit value and has no
failure result.

Cloud Play (PPSA99600) imports it: the import audit in #3249 on main
ccf9ff90 lists `UISQ-dQzw28` `arc4random` among nine absent imports
("no PR or issue found"). The ps5-payload-dev SDK stubs (f5d40f02,
sce_stubs/libScePosixForWebKit.c) place arc4random, arc4random_buf and
fnmatch in libScePosixForWebKit; arc4random_uniform is in neither that
set nor libSceLibcInternal, so it is not added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 95da68017f6817abec785864e682530e9b135a2b)
2026-10-11 11:14:30 +00:00
Donson 16cfe85a38 fix(agc): evict resource-cache images with storage entries 2026-10-11 19:08:29 +08:00
Adrià Franch ddf6b8c984 test(libSceNpTrophy2): cover sceNpTrophy2ShowTrophyList, take the context argument 2026-10-11 13:08:03 +02:00
MarcZX100 58bf763e85 feat(libSceRudp): implement context query calls 2026-10-11 11:07:33 +00:00
Achraf Reyani 466c86255f feat(libkernel): implement pthread_mutexattr_gettype
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:05:46 +09:00
fablevoid 195682e190 fix(libc): watch direct memory mapped over its reservation on macOS
Register copied the protection it had recorded for pages it already
watched over the protection the kernel had just reported. A guest that
reserves address space, which registers it as PROT_NONE, then maps
direct memory over it read-write and registers it again kept the stale
PROT_NONE. Collect only write-protects pages with PROT_WRITE, so writes
to that memory were reported once and never again. With PPSA12544 on
the macOS port, the title menu text blinked and glyphs went missing.

Register now keeps a recorded protection only where its own write
protection explains what the kernel reports, and takes the kernel's
protection otherwise. A protected page that was mapped again also loses
its protected mark, so erase no longer restores the old protection over
the new mapping. The kernel is read under the lock, so a concurrent
Collect cannot protect a page between the read and the merge.

Test write_watch_mapped: a reservation, a mapping over it and a second
registration keep reporting writes, and a protected page reserved again
stays PROT_NONE.

AI-assisted: yes
2026-10-11 11:04:02 +00:00
Suery 6c96c2ee1e
fix(libSceNpTrophy2): return success from sceNpTrophy2ShowTrophyList
There is no system trophy UI, so the call returns success without showing a
list, like the other silent NpTrophy2 entry points; recorded in
docs/dev/TechnicalDebt.md. PPSA15552 (Dead Cells) calls it and
aborted on the NotImplemented exception.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Dqgm9nUKygsXzr6poJsHJ
2026-10-11 07:02:34 -04:00
MarcZX100 d26c9bcabc fix(libkernel): reject empty filesystem paths 2026-10-11 11:00:35 +00:00
Gustavo Ariel Gamarra Rojas a07ac32a77 test(agc): cover UNORM16 and SNORM16 exports in the alpha-to-coverage GPU test
The pixel program packs its color for the export format, and the test now draws with FP16, UNORM16 and SNORM16 exports: an alpha of 0.75 keeps the pixel, 0.25 drops it, and so does -0.5 with SNORM16. Passes on an RTX 3050, a Radeon 660M and lavapipe.
2026-10-11 08:00:05 -03:00
Gustavo Ariel Gamarra Rojas 109eb81d62 test(agc): check the MRT0 export formats alpha-to-coverage accepts
Formats 4, 5, 6 and 9 (FP16, UNORM16, SNORM16 and 32-bit float ABGR) decode with alpha-to-coverage; formats 1, 2 and 3, which carry no floating-point alpha, still throw.
2026-10-11 08:00:05 -03:00
Adrià 0f863c1022
Merge pull request #353 from adriadam10/feat/relinker-linux-desktop-entry
feat(relinker): write a desktop entry with the game icon for Linux executables
2026-10-11 12:59:31 +02:00
lendinglibrary 288ee89d2d fix(agc): split a compute dispatch over the workgroup count limit
A dispatch whose group count exceeds maxComputeWorkGroupCount aborted the
process; a software device (lavapipe) reports the spec minimum 65535, and
Ghost of Yotei (PPSA26344) dispatches 129199x1x1 in its presentation path.
The count is now recorded as consecutive vkCmdDispatchBase chunks of at
most the limit per dimension, each continuing the grid at its base offset
(a plain vkCmdDispatch would restart group ids at 0 and re-execute the
first chunk's workgroups), with a barrier between chunks so a later chunk
sees an earlier one's writes. Compute pipelines are created with
VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, which a nonzero base requires.

A split on NVIDIA throws instead of dispatching: measured on an RTX 5070
Ti, the driver drops the first workgroups of a vkCmdDispatchBase dispatch
with a nonzero base (reproduced with a standalone Vulkan program outside
this repository), so its 65535 Y/Z limits cannot be split through. A split
of a dispatch whose LDS lives in device memory also throws: its buffer
slot base is computed from gl_NumWorkGroups, which inside a chunk is the
chunk's count, so workgroups of different chunks would alias (a 1D X split
only works because the base degenerates to the group id).

Fixes #3212
2026-10-11 05:58:29 -05:00
Adrià Franch 33a1ca5d33 fix(relinker): skip the desktop entry for macOS output and use native paths
The Linux desktop entry was written for every non-Windows output, macOS
included since --macos landed. It is now written only for Linux output,
and its paths go through Io::NativePath/Utf8Path like the rest of the
relinker. An end-to-end test relinks for Linux, macOS and Windows.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:55:22 +02:00
Gustavo Ariel Gamarra Rojas 94f05530d9 refactor(agc): use the shared PROCMAP_QUERY lookup in GuestMemory
GuestMemory.cpp carried its own procmap_query fallback and a ProcMapsQueryFd that opened /proc/self/maps once, probed PROCMAP_QUERY and honoured APS5_NO_PROCMAP_QUERY, the same as HostMapping::QueryFd. It now includes HostMapping.hpp and calls HostMapping::QueryFd.
2026-10-11 07:55:11 -03:00
alfalfa-star 00648f71b0 test(agc): keep key bytes reused after a first write through the write-back
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:51:36 +02:00
alfalfa-star 63f06f2935 fix(agc): store a storage image's DCC keys at write-back only when not stored yet
MarkDirty stores uncompressed keys at an image's first write and marks
its uploaded keys uncompressed. The write-back stored them again,
whenever the key bytes did not read uncompressed. By then the title may
have reused the metadata memory: RIDE 4 (PPSA01599) frees its 1920x1088
render targets after the legal screen and Unreal Engine's small-block
allocator takes the 64 KiB key block that followed one of them. The
deferred write-back then filled the allocator's free lists with 0xff
and the title crashed popping one.

The write-back now stores keys only when the image's uploaded keys are
not uncompressed already, that is when no store at the first write or
an earlier write-back made them so since the keys were last read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:51:36 +02:00
hypermist ef5d2130f4 feat(libSceNpEntitlementAccess): declare sceNpEntitlementAccessGetGameTrialsFlag
PPSA08427 (Killing Floor 3) stops on main at start-up because its bundled
pros.sdk.Prospero.prx imports it:

pros.sdk.Prospero.prx.guest.prx: undefined symbol: y7JD1gfwyfA

The signature is unknown, so it is declared without parameters and
throws, like the other entitlement flag queries the title does not reach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo
2026-10-11 23:50:45 +13:00
Dean Galvin e7b4c05549 fix(shader): set a BDA-written page's bit inside the slot probe loop
note_bda_write loaded the chunk's page mask and set the page's bit after the probe loop, through a function variable holding the slot. NVIDIA 610.57.04 (Linux) never finishes a dispatch that takes that path: agc_driver_bda_device and agc_driver_flat_apertures_0, _2, _3, _4, _5 lose the device. The same load and conditional OpAtomicOr now run in the loop body, on the iteration that finds or claims the slot.
2026-10-11 23:50:11 +13:00
MarcZX100 b1b996b243 fix(libkernel): reject empty sceKernelOpen paths 2026-10-11 10:49:17 +00:00
Abdulrahman Elkordy abed1c4314 fix(libkernel): answer select on the standard descriptors
Dungeons (PPSA16064) calls select on descriptor 0 and stopped with
"select on descriptor 0 (not a libSceNet socket) not implemented".
Descriptor 0 is now never readable and descriptors 1 and 2 are always
writable, as for a console title with no input. The assumption is in
TechnicalDebt next to the termios entry for the same descriptors.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:48:29 +03:00
Abdulrahman Elkordy cbbccb4930 fix(libkernel): name the descriptor select cannot poll
The abort only said "select on descriptors that are not libSceNet
sockets", which leaves no way to tell from a title's log what it waited
on. It now names the descriptor and says whether libSceNet was loaded.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:48:29 +03:00
Abdulrahman Elkordy 1f50b91280 fix(libkernel): report /dev/urandom descriptors ready in select
select passed every descriptor it was given to the libSceNet socket poller
and aborted on any it did not know. A title that selects on its
/dev/urandom descriptor (Dungeons, PPSA16064, aborts right after opening
it) stopped with "select on descriptors that are not libSceNet sockets".
On FreeBSD the random device is always readable and writable, so these
descriptors are now answered without the poller, and a ready one makes
the socket poll return at once.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:48:29 +03:00
Adrià 9a9bd3fb3c
Merge pull request #2369 from karanvora2599/perf/shader-coherent-alias
perf(shader): load from buffers without Coherent when the load has no GLC or DLC
2026-10-11 12:47:46 +02:00
David 9bec190733 feat(libSceAgc): implement sceAgcDebugRaiseException
sceAgcDebugRaiseException (NID T6xuVw0KUJo) now logs the exception id
with APS5_LOG_OUT and returns 0, as libkernel's
sceKernelDebugRaiseException does.

Palworld PPSA23126 (#2598) and 007 First Light PPSA11386 (#2523) import
it; neither is shown calling it.

OpenAGC 3c7e8072 (src/game_compat.c) returns 0 and says the function is
a no-op on retail hardware; the ud2 trap it describes for development
hardware is not reproduced. KytyPS5 6f0cddd4 (src/libs/agc.cpp) takes a
uint32 exception_id, logs it and returns 0. OpenAGC declares no
arguments, but a body that only traps reads none, so the uint32 is kept
and the conflict is recorded in TechnicalDebt. The aerolib name is from
zecoxao/sce_symbols 2883963a; ps5-payload-dev/sdk f5d40f02 has only an
untyped stub.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 07:47:33 -03:00
MarcZX100 1a793b3698 test(libkernel): tolerate process-time clock skew 2026-10-11 10:46:48 +00:00
Adrià 74f51a4c7d
Merge pull request #3440 from alfalfa-star/fix/guest-unmap-hole-inside-allocation
fix(libc): skip holes inside an allocation when unmapping a range
2026-10-11 12:46:05 +02:00
ivica00 cb52ca10c9 fix(shader): return 0 from 8-bit sRGB color comparison
image_sample_c_lz on gfx1035 returns 0 for 8-bit sRGB, so the unorm clamp was the wrong result. Bilinear cube comparison without DISABLE_CUBE_WRAP keeps throwing because that filter blends across faces.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 12:44:53 +02:00
Adrià Franch 7a0d708e70 docs(technical-debt): record the NVIDIA proprietary pipeline relink skip 2026-10-11 12:44:52 +02:00
Yuvaraj b29133c74e fix(agc): skip the background pipeline relink on NVIDIA's proprietary driver
On an RTX 4060 (Ada, driver 617.42) the optimized link of a pipeline built
from libraries loses the device (VK_ERROR_DEVICE_LOST) as soon as it is
bound, which fails agc_driver_pixel_valid_mask in 16 of 20 runs. With
APS5_NO_PIPELINE_LTO=1 it passes 20 of 20. Reporters see the same loss on an
Ampere card with a depth attachment; two Blackwell cards do not lose it.

A device whose driver is VK_DRIVER_ID_NVIDIA_PROPRIETARY keeps the
fast-linked pipeline and no longer queues the link-time-optimized relink.
Other drivers are unchanged.

Refs #2866

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 12:44:46 +02:00
Gustavo Ariel Gamarra Rojas 4bc36a4865 refactor(libc): define the PROCMAP_QUERY permission flags in HostMapping
GuestMemory.cpp reads PROCMAP_QUERY_VMA_READABLE and PROCMAP_QUERY_VMA_WRITABLE from the query result. The fallback for kernel headers without PROCMAP_QUERY now defines them too, so GuestMemory can use this header instead of its own copy.
2026-10-11 07:44:34 -03:00
Dani 21f4be11ad fix(libkernel): inherit process affinity in new guest threads 2026-10-11 12:44:26 +02:00
Adrià 74981fabe1
Merge pull request #3439 from babyhuey/feat/libkernel-sys-fstatfs
feat(libkernel_sys): export fstatfs
2026-10-11 12:42:21 +02:00
MarcZX100 8c06d20f6a fix(filesystem): reject final dot removal paths
Co-authored-by: milescoviello <kitslayer29@gmail.com>
2026-10-11 10:42:14 +00:00
Adrià 03a84d02a9
Merge pull request #3392 from MarcZX100/codex/fchdir-3288
feat(libkernel_sys): implement fchdir
2026-10-11 12:40:41 +02:00
MarcZX100 85b60b65d1 fix(recompiler): fold unordered infinity comparisons 2026-10-11 10:40:37 +00:00
Adrià 2e40ade881
Merge pull request #3402 from GalaxyGamingFR/fix/conventions-system-dependency-spelling
fix(conventions): match ordinary CMake spellings of system lookups
2026-10-11 12:39:31 +02:00
Adrià Franch ca330dfefb fix(relinker): validate the desktop entry before writing the executable
The icon, title and output path are checked before the ELF is written,
so a malformed icon0.png or param.json leaves no output behind. Paths
with control characters are refused instead of producing an invalid
entry.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:39:14 +02:00
Adrià Franch 1ff7b534fe feat(relinker): write a desktop entry with the game icon for Linux executables
ELF has no icon resource, so when sce_sys/icon0.png sits beside the input
the relinker copies it next to the output and writes <output>.desktop
(freedesktop Desktop Entry) with that icon. Name is the param.json title
without trademark signs or line breaks, or the output name without
param.json. Exec is quoted per the spec and the entry is marked executable
so file managers launch it. A malformed icon0.png or param.json fails the
relink; without icon0.png nothing extra is written.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:39:14 +02:00
Hannah Lyons 2741e96172 feat(libkernel): implement pthread_getthreadid_np 2026-10-11 06:38:14 -04:00
Adrià 6554fcb68a
Merge pull request #3430 from AchrafReyani/feat/libkernel-sigtimedwait
feat(libkernel): export sigtimedwait
2026-10-11 12:36:53 +02:00
Adrià f8d9b770c5
Merge pull request #3431 from fable-void/pr/macos-guest-absolute-symbols
fix(relinker): accept absolute symbols in macOS guest modules
2026-10-11 12:36:48 +02:00
Adrià f6d156a72e
Merge pull request #3435 from alfalfa-star/fix/playgo-package-chunk-table
fix(libScePlayGo): take the chunk set from sce_sys/playgo-chunk.dat
2026-10-11 12:36:22 +02:00
Adrià 0e442a4fee
Merge pull request #3433 from Feuris/carry/libkernel-truncate
feat(libkernel): export truncate and report EISDIR for a directory
2026-10-11 12:36:19 +02:00
Alex Collini 687f73c951 fix(agc): select the registered back half for a fused hull header
sceAgcFuseShaderHalves returns a fused hull as a copy of its back half
(type 7) that is not registered: type 3, no user data, and shader
registers copied to scratch memory with the checksum, RSRC1/RSRC2 and
the LS program address rewritten. sceAgcCreatePrimState accepts only that
type-3 header, and graphics ABI resolution refused it as a replaced
shader header.

SameHeader now also takes a type-3 header as the registered type-7
header for the same code when every other field is equal and its shader
registers differ only in the fused ones. Graphics ABI resolution then
applies the bound header's shader registers over the registered state.

PPSA26344 fuses its hull halves during its loading screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:36:01 +02:00
Adrià c064e6898e
Merge pull request #3425 from oneandonlydean/up4/fix-3158-span-limit
perf(agc-driver): join host-import spans only over whole aligned windows
2026-10-11 12:35:57 +02:00
Adrià a94f426a75
Merge pull request #3429 from CouchRiv/fix-libc-hypot-special-value
fix(libc): hypot returns +inf when one operand is infinite
2026-10-11 12:35:51 +02:00
Adrià 02030f8a62
Merge pull request #3427 from AchrafReyani/fix/pr-overlap-fetch-head-sha
fix(tools): fetch each open pull request by the head commit the API reports
2026-10-11 12:35:24 +02:00
alfalfa-star f3a2dcff7d test(libkernel): map fixed over a hole inside a direct allocation
One 4-page direct mapping loses its second page to munmap, then pages
1-2 are mapped fixed. The range starts in the hole; before the fix the
unmap of the overlap threw "guest protection or unmap range has a
hole". The pages around it keep their data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:34:12 +02:00
Abdulrahman Elkordy 2ba139df67 fix(libkernel): answer select on the standard descriptors
Dungeons (PPSA16064) calls select on descriptor 0 and stopped with
"select on descriptor 0 (not a libSceNet socket) not implemented".
Descriptor 0 is now never readable and descriptors 1 and 2 are always
writable, as for a console title with no input. The assumption is in
TechnicalDebt next to the termios entry for the same descriptors.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:34:07 +03:00
Abdulrahman Elkordy a670e93a88 fix(libkernel): name the descriptor select cannot poll
The abort only said "select on descriptors that are not libSceNet
sockets", which leaves no way to tell from a title's log what it waited
on. It now names the descriptor and says whether libSceNet was loaded.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:34:07 +03:00
Abdulrahman Elkordy 259b9ca630 fix(libkernel): report /dev/urandom descriptors ready in select
select passed every descriptor it was given to the libSceNet socket poller
and aborted on any it did not know. A title that selects on its
/dev/urandom descriptor (Dungeons, PPSA16064, aborts right after opening
it) stopped with "select on descriptors that are not libSceNet sockets".
On FreeBSD the random device is always readable and writable, so these
descriptors are now answered without the poller, and a ready one makes
the socket poll return at once.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 13:34:07 +03:00
ivica00 fc7446590a fix(shader): compare sRGB colors and bilinear cube faces
Subnautica Below Zero stops while compiling a menu shader that compares an sRGB color texture or a bilinear cube face. sRGB uses the unorm reference clamp, and a bilinear cube sample stays on the face it hits.

Written with AI assistance.
2026-10-11 12:32:28 +02:00
alfalfa-star 04ed619574 fix(libc): skip holes inside an allocation when unmapping a range
GuestAllocationsUnmap took the piece containing the cursor from the
allocation's original extent. After part of an allocation was unmapped,
a later unmap or fixed map starting in that hole still matched the
allocation, and replaceRange threw on the hole. Match against the
registered range itself and end each piece at its end. RIDE 4
(PPSA01599) maps fixed over a partly unmapped direct memory range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:32:12 +02:00
alfalfa-star 6a4ac0c629 docs(libScePlayGo): record where the chunk set comes from
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:30:52 +02:00
alfalfa-star 3ef8556ada test(libScePlayGo): take the chunk set from a package chunk table
A child process runs from a root whose app0/sce_sys/playgo-chunk.dat
declares 3 chunks: ids 0-2 are local, id 3 is rejected with
SCE_PLAYGO_ERROR_BAD_CHUNK_ID and scePlayGoGetChunkId counts 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:30:52 +02:00
Hannah Lyons 81075a66c6 feat(libkernel_sys): export fstatfs 2026-10-11 06:30:50 -04:00
alfalfa-star eb7da6680f fix(libScePlayGo): take the chunk set from sce_sys/playgo-chunk.dat
Without playgo-chunkdefs.xml every chunk id was accepted, so a title
that probes chunk ids until SCE_PLAYGO_ERROR_BAD_CHUNK_ID never stops.
RIDE 4 (PPSA01599, Unreal Engine 4) grows its chunk list until it runs
out of memory. The package's chunk table header holds the chunk count
at offset 0x0A; ids below it are valid. Every id is still accepted only
when neither file exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:29:45 +02:00
MarcZX100 1a73d0165e fix(libkernel_sys): use C ABI for fchdir helpers 2026-10-11 10:26:53 +00:00
MarcZX100 dc818b3ca6 fix(libc): keep chdir resolution atomic 2026-10-11 10:26:53 +00:00
Tharun Balaji 5a8091fafd feat(libkernel_sys): implement fchdir
FreeBSD fchdir(2) changes the working directory to the directory referenced by a descriptor. The guest imports fchdir from libkernel_sys (PPSA99764, issue #1578) and the module did not export it.

The descriptor's directory is resolved from the path recorded when the directory was opened on Windows, and from the /proc/self/fd link target on Linux. The guest working directory is then set through the libc routine shared with chdir. A descriptor that is not open returns EBADF and one that is not a directory returns ENOTDIR.

AI-assisted: yes
(cherry picked from commit 76329cbb08781e13d757c3ff955acf71f8bd506f)
2026-10-11 10:26:53 +00:00
Adrià 99c1c26347
Merge pull request #3426 from MathiasDevelopes/codex/agc-clear-state-mask
fix(agc): mask clear-state command to four bits
2026-10-11 12:24:18 +02:00
Adrià 8fcd352f04
Merge pull request #3420 from gookie-dev/perf/agc-lazy-constant-ram
perf(agc): allocate a queue's constant RAM on its first write
2026-10-11 12:23:06 +02:00
Adrià ce4263b1a6
Merge pull request #3423 from hawwwwwk/pr/relinker-instruction-length-current
fix(relinker): reject x86 instructions exceeding 15 bytes
2026-10-11 12:22:21 +02:00
Adrià 88636aaf02
Merge pull request #3419 from gookie-dev/perf/agc-registers-foreach
perf(agc): walk register sets by their bit words when resolving ABIs
2026-10-11 12:21:53 +02:00
Adrià 0809bcc8ae
Merge pull request #3421 from DariusHQ/feat/libkernel-ucontext-freebsd
feat(libkernel): implement getcontext, setcontext and makecontext
2026-10-11 12:21:46 +02:00
GalaxyGamingFR 0e7ccce2ec fix(conventions): match ordinary CMake spellings of system lookups
The system-dependency rule was case-sensitive, so FIND_PACKAGE(SDL2) passed,
and its trailing word boundary failed when whitespace followed the opening
parenthesis. find_path, find_program and find_file were not covered at all.
The pattern is now case-insensitive, anchors each command name, and covers
the find_* family.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:21:30 +02:00
Adrià 4611e9435c
Merge pull request #3424 from AchrafReyani/feat/libc-rand48
feat(libc): implement erand48, nrand48 and jrand48
2026-10-11 12:21:04 +02:00
Adrià dcca02896e
Merge pull request #3406 from GalaxyGamingFR/fix/stubgen-debt-links
fix(tools): make stubgen TechnicalDebt links resolve from docs/dev
2026-10-11 12:20:37 +02:00
Achraf Reyani 2a2696bd9c feat(libkernel): export sigtimedwait
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:20:16 +09:00
Mouad a584bc6a01 feat(libkernel): export truncate and report EISDIR for a directory
`truncate` (`ayrtszI7GBg`) is an absent import of PS5MC (PPSA99420),
XPSemu (PPSA97358) and Porpoise (PPSA99764) on `main`. It resolves
through `sceKernelTruncate`, which now returns `EISDIR` for a directory
and the host errno for other failures instead of `EIO`, as FreeBSD 11
`kern_truncate` does. The guest-relative test `guest_truncate` covers
shrinking, growing with zero fill, a negative length, a missing path,
an empty path, a null path, a directory and a read-only file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 07:19:35 -03:00
Adrià 68ae2a895d
Merge pull request #3386 from GalaxyGamingFR/fix/conventions-path-with-spaces
fix(conventions): keep per-line rules for file names with spaces
2026-10-11 12:19:02 +02:00
Alex fc0994876d fix(libc): hypot returns +inf when one operand is infinite
hypot(inf, NaN) returned a NaN on main. C Annex F returns +inf when
either operand is infinite, even if the other is a NaN, and FreeBSD
msun (lib/msun/src/e_hypot.c) does so for a signalling NaN too. The
infinite case is now checked before std::hypot; other inputs do not
change.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 06:17:21 -04:00
fablevoid 3462427519 fix(relinker): accept absolute symbols in macOS guest modules
#698 taught the reader, the module builder and the Windows writer to
resolve relocations against SHN_ABS symbols and to leave them out of the
exports, but the macOS writer still threw "Unsupported guest export
section" for them. PPSA12544 bundles modules with such an export
(RKDbTdN8TO0), so --macos stopped before writing anything.

The macOS writer now resolves a relocation against an absolute symbol to
its value plus the addend, without a rebase, and skips absolute symbols
when exporting, as the Windows writer does. guest_absolute_symbols covers
the macOS output too.

AI-assisted: yes
2026-10-11 10:16:59 +00:00
Adrià e7827eb4d4
Merge pull request #3416 from AchrafReyani/fix/nodiscard-warnings
fix(shader): discard two nodiscard results explicitly
2026-10-11 12:16:54 +02:00
Adrià a7d80e7413
Merge pull request #2410 from karanvora2599/perf/shader-pack-conversions-f32
perf(shader): round v_cvt_pknorm and v_cvt_pk_u8 in f32
2026-10-11 12:16:07 +02:00
Adrià f0c6cf27b2
Merge pull request #3408 from GalaxyGamingFR/fix/pr-overlap-template-placeholder
fix(tools): read Depends on through the template placeholder in pr_overlap
2026-10-11 12:13:59 +02:00
Achraf Reyani 2b234efff3 fix(tools): fetch each open pull request by the head commit the API reports
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:13:35 +09:00
Hussein Kadhim 60b1318226 docs(technical-debt): list the float exponent quirk with the scanf host differences 2026-10-11 12:12:48 +02:00
Hussein Kadhim 09921dd376 fix(libc): return 0 from scanf when input fails after a suppressed conversion on Windows
C17 7.21.6.2p16 returns EOF only if input fails before the first conversion completes, and a suppressed conversion completes. FreeBSD counts it in nconversions (vfscanf.c, releng/11.4, lines 799-805). The host scanf returned EOF there, so sscanf("12", "%*d%d", &v) reported EOF instead of 0. Each suppressed conversion now records its end with a %n and a result of EOF becomes 0 when one was recorded.
2026-10-11 12:12:48 +02:00
Adrià 2ac9f1b317
Merge pull request #3414 from AchrafReyani/fix/process-time-test-wait
test(libkernel): wait until 50 ms have passed before the first process time read
2026-10-11 12:12:44 +02:00
Adrià 74c0f1bd14
Merge pull request #3409 from GalaxyGamingFR/docs/contributing-depends-on
docs: show the Depends on form the conventions check accepts
2026-10-11 12:11:49 +02:00
MathiasDevelopes 46d8c587c6 fix(agc): mask clear-state command to four bits 2026-10-11 12:11:03 +02:00
Adrià f100f6c7fc
Merge pull request #2786 from tototomate123/fix/hfw-loader-split
fix(loader): resolve sceKernelDlsym on the main module
2026-10-11 12:10:04 +02:00
Adrià b42b29128b
Merge pull request #3407 from GalaxyGamingFR/fix/import-audit-per-library-stubs
fix(tools): classify import_audit stubs per providing library
2026-10-11 12:09:27 +02:00
Adrià 3bf63fadce
Merge pull request #3401 from AchrafReyani/carry/pipodi-3350
fix(recompiler): split descriptor webs selected per lane
2026-10-11 12:08:57 +02:00
Adrià 6cee0bb02a
Merge pull request #3400 from AchrafReyani/carry/pipodi-3349
fix(recompiler): evaluate an out-of-range constant buffer read as zero
2026-10-11 12:08:15 +02:00
boykopovar cfbd516c24
Merge pull request #3397 from boykopovar/feat/show-guest-prx-processing
feat(relinker): show guest prx processing
2026-10-11 13:07:42 +03:00
Adrià Franch 68f60cf348 fix(conventions): spell the stripped tab as an escape 2026-10-11 12:07:35 +02:00
GalaxyGamingFR 3a1deb48a8 fix(conventions): strip trailing tab from spaced diff paths
Git appends a tab after file names containing spaces in the +++ header, so the
added-lines key kept the tab and its suffix no longer matched. Comment,
extension, title and silent-stub rules then skipped such files. The tab is
now stripped, with a test covering core/a b.cpp.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:07:34 +02:00
Adrià 434f290def
Merge pull request #3403 from babyhuey/feat/libkernel-link
feat(libkernel_sys): implement link
2026-10-11 12:06:51 +02:00
Adrià a4d5d3ce53
Merge pull request #545 from Pouare514/feat/ampr-c-runtime
feat(libs): implement C runtime re-exports for libSceAmpr
2026-10-11 12:06:18 +02:00
Adrià cdef5b7fce
Merge pull request #3405 from GalaxyGamingFR/fix/pr-overlap-encoding
fix(tools): decode pr_overlap git output with errors=replace
2026-10-11 12:05:54 +02:00
Adrià 106d446a33
Merge pull request #3380 from Feuris/feat/libc-abs
feat(libc): implement abs
2026-10-11 12:05:14 +02:00
Hussein Kadhim 7195e355b4 docs(technical-debt): list the doubled strftime modifier among the host differences 2026-10-11 12:05:00 +02:00
Hussein Kadhim 84926887e9 fix(libc): keep the literal percent after E and O in strftime
A format such as %E%k is a modified percent sign followed by a literal k, so the second percent must not start a new conversion.
2026-10-11 12:05:00 +02:00
Hussein Kadhim c5bc118f4b fix(libc): accept E and O before new strftime conversions and take %+ zone from tm 2026-10-11 12:05:00 +02:00
Hussein Kadhim 7e3a409022 fix(libc): format %k, %l, %s, %v and %+ in strftime 2026-10-11 12:05:00 +02:00
Achraf Reyani f85ae8d6f2 feat(libc): implement erand48, nrand48 and jrand48
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:02:32 +09:00
Adrià 24cb0d2412
Merge pull request #3389 from semirkabir/feat/usbd-no-devices
feat(libSceUsbd): implement transfer allocation and event handling for the no-device path
2026-10-11 12:02:06 +02:00
ethan f2ef0f9557 fix(relinker): reject x86 instructions exceeding 15 bytes
(cherry picked from commit 7243caa56ed79fab09edd23d92851e2508671775)
2026-10-11 03:02:05 -07:00
gookie 8b550b81fc perf(agc): allocate a queue's constant RAM on its first write
QueueState held the 48 KiB constant RAM inline, so every QueueState
cleared 48 KiB when constructed and copied it when copied.
ResolveShaderAbi and ResolveGraphicsStagesAbi construct one on each call
(sceAgcLinkShaders, sceAgcCreatePrimState, interpolant mapping),
resolveGroupAhead copies the live state, and a queue reset builds a new
one, although few command buffers write the constant RAM.

The constant RAM is now a vector allocated when WRITE_CONST_RAM first
writes it. ConstantRam returns a shared all-zero view until then, so
DUMP_CONST_RAM of unwritten words still stores zeros, and the bounds use
QueueState::ConstantRamWords. The store view ResolveStore returns is
copied by the recorder within the packet, as before.

testMemory dumps unwritten constant RAM and checks for zeros, and checks
that a copied queue state keeps the words written before the copy.

A QueueState is 336 bytes instead of 49464; constructing one takes 0.3
to 0.8 us instead of 1.5 to 2.1 us, and copying one 0.4 to 0.6 us
instead of 1.9 to 3.8 us (GCC 13 -O3). On the title screen of PPSA21402
(Balatro) the clears from the two resolvers took 30 to 129 of 3459 to
7838 CPU samples per 10 s.
2026-10-11 12:01:27 +02:00
Adrià Franch 52a5b4869a fix(tools): drop unused depends lookup in open_prs 2026-10-11 12:01:08 +02:00
GalaxyGamingFR 26e0b30df3 fix(tools): ignore PR template placeholder when reading dependencies
The PR template's untouched "Depends on: <!-- #PR, or none -->" line
matched the checklist regex, so prose such as "Depends on #1400" was never
consulted and the declared dependency was lost. HTML comments are now
stripped and the prose form is used when the checklist line is blank. An
explicit "Depends on: none" still takes precedence.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 12:01:08 +02:00
DariusHQ cf1545d751 feat(libkernel): implement getcontext, setcontext and makecontext
PSXS5, SwanStationPS5 and Nuvio stop at start-up on setcontext on main,
and EVO Player and ProsperoStore do on Windows. The three are imported
by the statically linked OpenSSL's ASYNC code.

The three use FreeBSD 11's amd64 ucontext_t (mcontext at 0x10, mc_len
800, uc_link at 0x330, 0x370 bytes), which the titles are built
against: EVO Player's ASYNC_is_capable captures into a 0x370-byte stack
buffer, and async_fibre_makecontext sets uc_link at 0x330 and uc_stack
at 0x338. getcontext saves every register at its call in assembly and
stores the context as FreeBSD's sys_getcontext does: rax and rdx as 0,
the carry flag clear, the FXSAVE image and the signal mask, and nothing
from uc_link on. setcontext checks mc_len and mc_flags as set_mcontext
does, installs the signal mask, masks MXCSR with the host's MXCSR_MASK
and returns through iretq, so every general register and the flags are
restored and nothing is written below the target stack pointer.
makecontext follows FreeBSD 11's amd64 libc.

Windows checks guard-page growth and exception unwinding against the
stack bounds in the TEB. setcontext and longjmp now set them to the
stack they switch to, which makecontext registers and pins writable as
libSceFiber does for fiber stacks. OpenSSL enters a context with
setcontext and then switches with _setjmp and _longjmp.
2026-10-11 13:00:38 +03:00
gookie f596bde6f6 perf(agc): walk register sets by their bit words when resolving ABIs
Iterating a Registers advances with nextPresent, which recomputes the
word, mask and next bit from the index on every step, about 3.5 ns per
register. BuildRegisteredAbiKey walks all of a state's registers, about
300 with the context, and ResolveGraphicsStagesAbi walks each stage's
registered state to merge it, on every sceAgcLinkShaders,
sceAgcCreatePrimState and interpolant mapping call.

Registers::ForEach visits the set registers in ascending order straight
from the presence words, and both paths use it. The key and the merged
state are unchanged.

testRegisterFile checks that ForEach visits what iteration visits, in
order, and skips an erased register.

Building the key for 297 registers takes 200 ns instead of 1030 ns (GCC
13 -O3). On the title screen of PPSA21402 (Balatro) the two functions
took 0.18 to 0.29 CPU samples per sample of the title's own code, and
0.06 to 0.12 with this change.
2026-10-11 12:00:28 +02:00
Adrià 8ec0e13109
Merge pull request #3404 from GalaxyGamingFR/fix/conventions-checklist-bullets
fix(conventions): count * and + checklist bullets as unchecked
2026-10-11 11:59:14 +02:00
GalaxyGamingFR efbf36f637 fix(tools): make stubgen debt links resolve from docs/dev
stubgen emitted TechnicalDebt links as repo-relative paths, but
TechnicalDebt.md lives in docs/dev and the conventions checker resolves
links relative to it, so pasted lines failed CI. The derived default path
now carries a ../../ prefix; an explicit --td-path is used as given.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 11:58:25 +02:00
Adrià b44eeb967a
Merge pull request #3393 from LeandroLP23/fix/libc-printf-pointer-form
fix(libc): format %p as FreeBSD does on Windows
2026-10-11 11:58:03 +02:00
Adrià 708ffcd2ef
Merge pull request #3394 from LeandroLP23/fix/kernel-signal-unmapped-numbers
fix(libkernel): accept signal() for every valid signal number
2026-10-11 11:56:52 +02:00
Adrià 58a581d983
Merge pull request #3399 from MathiasDevelopes/codex/feat-npwebapi2-push-event-abort
feat(libSceNpWebApi2): export sceNpWebApi2PushEventAbortHandle
2026-10-11 11:56:32 +02:00
boykopovar 651edc39f5 test(relinker): expect self containers to be skipped 2026-10-11 12:56:17 +03:00
Adrià ec77a616b6
Merge pull request #3395 from LeandroLP23/fix/kernel-mkdir-enotdir
fix(libkernel): report ENOTDIR from mkdir and rmdir when a path component is a file
2026-10-11 11:55:48 +02:00
Adrià 76f2d72d40
Merge pull request #3384 from sypher69/fix/sce-dynlibdata-relocation-offsets
fix(relinker): resolve SCE relocation tables relative to dynlibdata
2026-10-11 11:55:28 +02:00
Achraf Reyani 0eaf2ec159 test(libkernel): wait until 50 ms have passed before the first process time read
sleep_for can return up to a scheduler tick early against the
performance counter the guest clock reads, so the first reading could be
just under 50 ms on a loaded machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:51:47 +09:00
Adrià 5c4bc7d607
Merge pull request #3390 from GalaxyGamingFR/fix/check-skips-device-messages
fix(ci): recognise every device-limitation skip message in check_skips
2026-10-11 11:51:46 +02:00
Adrià b70a0e278f
Merge pull request #1491 from Celegans12/feat/shader-tessellation-triangle-patches
feat(shader): implement triangle-patch tessellation
2026-10-11 11:50:50 +02:00
tototomate123 4a62b6220b fix(build): export the Windows dynamic loader test executable 2026-10-11 11:50:44 +02:00
tototomate123 19b0359f13 fix(loader): support main-module sceKernelDlsym 2026-10-11 11:50:44 +02:00
Adrià Franch af9dfbfab9 test(libs): report the failing guest_crt check and compare localeconv per module
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:49:34 +02:00
Hannah Lyons 0e8dc6f20f feat(libkernel_sys): implement link 2026-10-11 05:47:59 -04:00
Achraf Reyani 30a3cbea7d fix(shader): discard two nodiscard results explicitly
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:45:44 +09:00
Adrià a73a1af9c8
Merge pull request #3382 from babyhuey/feat/libkernel-readv
feat(libkernel): implement readv and writev
2026-10-11 11:43:45 +02:00
MathiasDevelopes 6d70a46f74 docs: remove gap between technical debt entries 2026-10-11 11:43:36 +02:00
MathiasDevelopes 0f45675768 feat(libSceNpWebApi2): export sceNpWebApi2PushEventAbortHandle
Titles that import it now load; calling it throws until push event
handles have operations that can be aborted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit f50cb08c988736d645f0cc1c329f911f732fa935)
(cherry picked from commit ae3227dbfa2c972b36242056df5971d858ac65c3)
(cherry picked from commit 3df66a6a5dd9f0cd73daaee1342c22742c1915e4)
2026-10-11 11:43:35 +02:00
GalaxyGamingFR 9c42733c46 docs: show the Depends on form the conventions check accepts
CONTRIBUTING.md told authors to write `Depends on #N` in the
description, but the pr-template rule in tools/check_conventions.py
only accepts the checklist line `Depends on: #N` or `Depends on: none`
from the pull request template. A pull request that followed the
document failed the Conventions job with "fill Depends on with #N or
none". The sentence now shows the checklist form.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:43:06 -07:00
Alex Collini f3e654a4f5 fix(recompiler): split descriptor webs selected per lane
A T# picked per lane with SelectU32 and made uniform with
v_readfirstlane, as in a waterfall loop, left a descriptor web without
Phis that the web walk could not split. CollectDescriptorPhis now steps
through ReadFirstLane, and a Phi-free tuple containing SelectU32 or
ReadFirstLane is split on the shared condition (SelectU32) or wrapped in
a matching ReadFirstLane. The new nodes are placed after the last
original node of the tuple in its block and inserted only when the web
is split; otherwise they are invalidated like the web's Phis.

PPSA26344 compute shader 0x800037f200 selects its T# per lane between
SRT reads or zero and reads the first lane of the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:42:56 +09:00
Alex Collini 5a9d731540 fix(recompiler): evaluate an out-of-range constant buffer read as zero
s_buffer_load returns zero for dwords outside the V#'s range. The SRT
evaluator refused such a read instead, so evaluating a descriptor failed
as soon as one arm of a split T# read through a null or short V#, even
when that arm is never taken. The evaluator now returns zero for those
reads, as the hardware does.

PPSA26344 compute shader 0x800037f200 reads one arm's T# through a null
V# and stopped at "SrtWalker::EvaluateRuntimeSources failed to evaluate
runtime sources".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:42:47 +09:00
GalaxyGamingFR 50c288810e fix(tools): key import audit stubs by library
source_stubs pooled done NIDs across all libraries, so a throwing stub
in libSceShare.native counted as implemented when libSceShare had the
same function. Stubs are now keyed by (library.prx, nid) and audit marks
an import stub only when every provider of it is a stub.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:42:36 -07:00
Pouare514 5290f92876 fix(libs): share Sony CRT semantics between libc and libSceAmpr with tests 2026-10-11 11:42:31 +02:00
GalaxyGamingFR 15f34d3043 fix(tools): decode pr_overlap git output with errors=replace
One PR diff containing a byte that is not valid UTF-8 made git() and
merge() raise, which aborted the hourly run and dropped the overlap
comment on every PR. Both subprocess calls now pass errors="replace",
matching check_conventions.py. A test commits a Latin-1 byte and checks
the export is still found.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:42:08 -07:00
GalaxyGamingFR 2f1b4aaf97 fix(conventions): count * and + checklist bullets as unchecked
The pull request check only matched unchecked items written with a dash,
so a checklist rewritten with * or + bullets passed with every box empty.
GitHub renders all three bullet styles as task items. The pattern now
accepts any of them, and new tests cover each bullet style.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:41:54 -07:00
Adrià dbc3b0679a
Merge pull request #2541 from maoxin1234/fix/sysmodule-trophy2-module-id
fix(libSceSysmodule): register Trophy2 module ID
2026-10-11 11:41:43 +02:00
Feuris e2b11c2dd8 feat(libc): implement abs 2026-10-11 06:41:00 -03:00
Adrià 946ffa08d4
Merge pull request #3372 from alfalfa-star/fix/agc-fast-clear-import-window
fix(agc): keep a fast-clear copy where an import window can stamp watched memory
2026-10-11 11:40:15 +02:00
Semir Kabir cbd18363bd feat(libSceUsbd): implement transfer allocation and event handling for the no-device path 2026-10-11 09:40:14 +00:00
Adrià a31732c5ff
Merge pull request #3365 from MathiasDevelopes/codex/fix-windows-unscoped-imports
fix(relinker): load needed providers for unscoped Windows imports
2026-10-11 11:40:05 +02:00
Adrià 9a1f6f44ac
Merge pull request #3379 from CouchRiv/fix-shader-fold-bitreverse32
fix(shader): fold BitReverse32 of an immediate
2026-10-11 11:39:04 +02:00
Adrià 66d577d428
Merge pull request #3378 from GalaxyGamingFR/fix/conventions-quoted-paths
fix(conventions): read non-ASCII paths unquoted from git
2026-10-11 11:37:57 +02:00
Adrià Franch c8f8014ea2 docs(debt): local programs get one artifact per tessellation configuration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:37:19 +02:00
Hannah Lyons 63a4014236 feat(libkernel): implement readv and writev 2026-10-11 05:36:38 -04:00
Adrià 097f4e2284
Merge pull request #3373 from MathiasDevelopes/codex/feat-coredump-thread-context-export
feat(libkernel): export sceCoredumpGetThreadContextInfo
2026-10-11 11:36:29 +02:00
Dean Galvin 8da461ba51 perf(agc-driver): fix the host-import window at 8 MiB
The window was read from APS5_HOST_IMPORT_WINDOW_MIB on the device.
It is now always 8 MiB, the value the previous commit was measured
with; SetHostImportWindow stays for the tests. TechnicalDebt records
the window as a choice.
2026-10-11 22:35:37 +13:00
maoxin1234 5ee3ef8cb8 fix(libSceSysmodule): recognize Trophy2 module id 2026-10-11 11:35:37 +02:00
Cesar Rodriguez a947303731 perf(agc-driver): join host-import spans only over whole aligned windows
one span. A title that grows a heap 16 KiB at a time then re-imports the
whole chain on every growth: Ratchet & Clank: Rift Apart re-imported about
1.5 TiB while loading its first scene, and NVIDIA refused grown spans with
VK_ERROR_OUT_OF_DEVICE_MEMORY, which leaves those ranges copied per draw.

Ranges are now joined only when a chain covers a whole aligned window (8 MiB
by default, APS5_HOST_IMPORT_WINDOW_MIB on the device); until the window is
complete each range is imported on its own, and a span never crosses a
window edge. Growth therefore re-imports a range once more at most when its
window completes, instead of the chain on every growth. Joining any part of
a window was tried first and still re-imported 2 GB per second in Ratchet,
as each growth re-imported the window's partial span. A single range larger
than the window is imported whole. SetHostImportWindow(0) keeps the
unbounded spans, which is what the existing tests use.

The new importWindowTests (agc_driver_graphics) checks that a full window is
one span, that a partly filled window imports its range alone, that a view
crossing a window edge gets no import, and that completing one window leaves
the other window's import in place; with the window ignored it fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:35:28 +13:00
Adrià af45296363
Merge pull request #1780 from Roojool/fix/avplayer-eof-wakeup
fix(avplayer): use precise Windows notified waits for EOF polling
2026-10-11 11:35:23 +02:00
Dani cdfc11cf56 fix(relinker): resolve SCE relocation tables relative to dynlibdata 2026-10-11 11:34:59 +02:00
Adrià f4b7151097
Merge pull request #2510 from Edd016/fix/hw-oracle-mingw-lld
fix(hw-oracle): select the AMDGPU ELF emulation when linking kernels
2026-10-11 11:33:58 +02:00
GalaxyGamingFR 73b4bdb600 fix(tools): accept more device limitation skips in check_skips
The Linux skip check only recognised subgroup, "the device has no",
"the device reports" and "no display", so tests that skip with
"the device lacks ...", "does not import", "imports no", "flushes",
"binds fewer", "no usable Vulkan device" or "host imports are
unavailable" failed the job. The regex now covers those messages, and
unrelated reasons such as "flaky" still fail. A unit test covers the
messages and an end-to-end run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:33:31 -07:00
boykopovar 480e68a84d fix(relinker): format module size to two decimal places 2026-10-11 12:33:21 +03:00
Adrià Franch de2f7aca22 test(relinker): drop docstring from loader path check 2026-10-11 11:33:17 +02:00
MathiasDevelopes 3f5c6e8336 test(relinker): remove disallowed loader test comments 2026-10-11 11:33:13 +02:00
MathiasDevelopes c245e3abc4 test(relinker): verify unscoped Windows provider load paths 2026-10-11 11:33:13 +02:00
MathiasDevelopes 2faa5dd6ed fix(relinker): load needed providers for unscoped Windows imports 2026-10-11 11:33:13 +02:00
Adrià 92ceadff7f
Merge pull request #3376 from adriadam10/ci/pr-open-limit
ci(pr): limit open pull requests by the author's merged count
2026-10-11 11:33:10 +02:00
GalaxyGamingFR 8365766e93 fix(conventions): read non-ASCII paths unquoted from git
With git's default core.quotePath=true, paths with non-ASCII characters
were printed quoted and octal-escaped. The checker stored the quoted
string as the path and then failed in git show with a traceback. git()
now passes core.quotePath=false so raw UTF-8 paths are used. A test
covers a diff containing a non-ASCII file name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
2026-10-11 02:32:41 -07:00
Adrià e608d40265
Merge pull request #2051 from esatturan/fix/libkernel-umtx-interruptible-waits
fix(libkernel): let exception delivery interrupt mutex and rwlock waits
2026-10-11 11:31:40 +02:00
Adrià 65d4a8b189
Merge pull request #3375 from MarcZX100/codex/libc-unlocked-streams-lockfree-1765
feat(libc): implement unlocked character I/O
2026-10-11 11:31:03 +02:00
Adrià Franch 48c9156d10 docs: remove stray blank line in the TechnicalDebt list 2026-10-11 11:28:44 +02:00
Adrià Franch 14f585a439 ci(pr): limit open pull requests by the author's merged count
Authors with no merged pull requests can have 1 open, with at least 1
merged 20, and from 20 merged there is no limit. Reopening a pull
request runs the check again.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:28:43 +02:00
MathiasDevelopes 92303a2ee5 feat(libkernel): export sceCoredumpGetThreadContextInfo
Titles that import it now load; calling it throws like the other
coredump queries, since host crashes are not turned into guest dumps.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit e0e5fd9ffbbaffdc065d1471ce1c91b144af5f98)
(cherry picked from commit 2ac0c88fdbb9e380b6eb5a37d5f98d557940f131)
(cherry picked from commit 1279010b1bc123d3b87664ede15ec6ab2ced806a)
2026-10-11 11:28:39 +02:00
Adrià c6ca798fe6
Merge pull request #1655 from mohdfaour03/fix/videoout-present-precise-wait
fix(videoout): wait for flips with the high-resolution condition on Windows
2026-10-11 11:27:48 +02:00
Adrià 0333ec91ed
Merge pull request #1482 from awake-devel/fix/libkernel-umtx-op
feat(libkernel): implement _umtx_op wait and wake operations
2026-10-11 11:26:12 +02:00
Adrià Franch a898efdb41 fix(shader): index hull control-point inputs with constant slots
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:25:56 +02:00
Adrià Franch e53e1762e3 test(agc): adapt the tessellation tests to the fixed push slots and preparation at use
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:25:56 +02:00
Celegans12 77dcb74ccd feat(shader): implement triangle-patch tessellation
DecodeShaderStages accepts LS, HS and an NGG passthrough ES, reads the
3-bit VGT_TF_PARAM fields, refuses its other bits but DISTRIBUTION_MODE,
and needs HOS levels that keep [1, 63]; 0x286-0x287 join the draw key.
Local and domain programs are prepared with their stage group: its
headers are merged over one set of defaults, and a local program left
unbound by the hull header is prepared at its first draw.

The local program ends at its jump into the hull half.
TessellationLowering lowers LDS and ring addresses that are affine in
the control point and relative index to tessellation interfaces with
strides from the code, and refuses accesses outside the patch, per-patch
writes from other control points and a modified primitive export. Hull
lanes read their own saved exec bit, also of host-subgroup-masked
copies; other masks are refused, gl_InvocationID loads as a scalar and
factors clamp to 63.
2026-10-11 11:25:56 +02:00
Alex d809958b27 fix(shader): fold BitReverse32 of an immediate
A descriptor dword built by S_BREV_B32, V_BFREV_B32 or S_BREV_B64 from a
constant stayed a runtime value, so the resource could not be resolved
and the shader failed to prepare. The constant folder now reverses the
bits of an immediate the way the hardware does (D[31-i] = S0[i]), like
the existing BitCount32 fold. ConstantBitTest covers the fold.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-11 05:23:40 -04:00
Adrià 09bd4aa1a3
Merge pull request #1431 from Zaid-Talib/claude/focused-turing-ivfmjn
feat(libkernel): deliver sceKernelRaiseException on Linux
2026-10-11 11:22:31 +02:00
Adrià 4c9686fe2e
Merge pull request #1388 from gjonn/feat/agc-color-compare-constant-swizzle
feat(agc): color compare through a view whose X channel is constant
2026-10-11 11:21:17 +02:00
esatturan be4ab94642 fix(libkernel): let exception delivery interrupt timed mutex and rwlock waits on Windows 2026-10-11 11:20:40 +02:00
Roojool 23b65eb553 fix(avplayer): use precise Windows notified waits for EOF polling
Waits on eventCondition go through libkernel's TimedWait::Condition (precise
timed waits on Windows) instead of std::condition_variable::wait_for, as
requested in review.
2026-10-11 11:20:24 +02:00
Adrià e272b92e03
Merge pull request #3368 from AchrafReyani/carry/libkernel-process-time-start
fix(libkernel): count process time from library load
2026-10-11 11:19:48 +02:00
Adrià Franch b41db48b7a fix(videoout): build TimedWait into libSceVideoOut instead of importing it from libkernel
libkernel.prx does not export TimedWait::*, so libSceVideoOut.prx had an
unresolved import and titles stopped at load. Compile TimedWait.cpp into
libSceVideoOut, and use NotifyAll for the notify added on main.
2026-10-11 11:19:05 +02:00
Mohd Faour 96890dee37 fix(videoout): wait for flips with the high-resolution condition on Windows
The flip queue's condition variable went through winpthreads, whose
timed waits end on GetTickCount64 steps: the present thread's 10 ms poll
for SDL events and the pad, taken while no flip is queued, ended 11 to
24 ms later on Windows, and WaitForFlipRoom's 60 s bound had the same
granularity. Use TimedWait::Condition, which waits on an event and a
high-resolution timer, so the poll ends at 10 ms and a submitted flip
still wakes the present thread at once.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 11:19:05 +02:00
Adrià 0490ca18dd
Merge pull request #1505 from Sanjaysrinivas/test/shader-half-expansion
test(shader): cover half expansion bit patterns
2026-10-11 11:18:31 +02:00
Romans Pokrovskis 228532e9a8 fix(libc): keep unlocked stream status queries lock-free
Use unlocked POSIX EOF/error queries after unlocked byte operations so status synchronization cannot reacquire the stream lock. Keep the verified UCRT status calls on Windows, and cover byte, status, error, and held-lock behavior.

Co-authored-by: MarcZX100 <marczxrr@gmail.com>
2026-10-11 09:18:23 +00:00
MarcZX100 753b856526 feat(libc): implement unlocked character I/O 2026-10-11 09:18:23 +00:00
milescoviello ee720ee004 test(agc): reproduce an import window over a pending storage image
agc_driver_dcc_keys_first_write only exercises the import window when the
device's own host import resolves the write protection of the imported
pages, as the NVIDIA driver does on Linux. CI's devices do not, so the
comparison that #2984 adds for BlockMaybeWritten units is not run there.

RunImportWindow opens an import window itself over a pending storage
image with GuestMemory::ImportWatched and stores the byte already there,
which leaves the same stamp without depending on the driver: the image
must stay pending and unchanged. A store of a new byte inside a window
must still be seen. Devices whose imports are compared print that the
window is not tested, as the recorder's (w) test does. Linux only: the
Windows path compares imports.

TechnicalDebt records that an identical-byte CPU store inside a window
cannot be told apart from the import, and that images tracked by layer
still upload again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:18:04 +02:00
milescoviello f774e1cd98 fix(agc): keep a fast-clear copy where an import window can stamp watched memory
range is write-watched. Since #2984, Refresh turns a BlockMaybeWritten
unit into BlockUnchanged only through compareUntracked, which needs that
copy. Where a host import leaves its range watched and making it stamps
the imported pages (the probe's writtenAtImport, 4 of 4 on NVIDIA's
Linux driver), the import window stamps the surface, so a pending
fast-cleared image counted as changed again and
agc_driver_dcc_keys_first_write failed on main (#3179).

HostImports now keeps whether making each kind of import stamped the
probe's pages, and WatchedImportsStampPages reports whether an import
that leaves its range watched can stamp it. The clear path skips the
copy only when no such import can, as oneandonlydean proposed in #3179.
Devices whose probe saw no pages written at the import, devices without
host imports and Windows (whose alias imports don't disarm the guest
views) keep #2699's saving.
An unprobed watch (APS5_WRITE_WATCH_IMPORTS=watch) keeps the copy.

The fast-clear check in agc_driver_dcc_keys_first_write now expects the
copy exactly when the range is unwatched or such a stamp is possible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:18:04 +02:00
Adrià 5ad2cb8cd0
Merge pull request #1377 from gjonn/fix/agc-unnormalized-base-level-view
fix(agc): sample the base level of mipmapped views with unnormalized coordinates
2026-10-11 11:17:05 +02:00
Adrià e8e4dfdb36
Merge pull request #3337 from AchrafReyani/carry/export-ppsa01530-ppsa13356-imports
fix(exports): export the calls PPSA01530, PPSA23827 and PPSA13356 import
2026-10-11 11:16:45 +02:00
Adrià bf5458b760
Merge pull request #1423 from gjonn/perf/libc-unwind-eh-frame-index
perf(libc): index .eh_frame and find unwind modules without a syscall
2026-10-11 11:16:13 +02:00
Adrià 3e1fa82cf2
Merge pull request #1416 from gjonn/fix/recompiler-sample-missing-coordinates
fix(recompiler): sample the first row when the address omits coordinates
2026-10-11 11:14:21 +02:00
Adrià Franch 3879e7ed54 fix(libkernel): throw on a size-0 _umtx_op timeout that is not a valid timespec 2026-10-11 11:13:33 +02:00
Zurisen 9ebc657f82 fix(libkernel): count process time from library load
sceKernelGetProcessTime and sceKernelGetProcessTimeCounter measured from
a start captured on their first call, so the first reading was about 0
however long the process had run, and exactly 0 when both reads fell in
one tick of the host clock (100 ns on Windows). Capture the start when
libkernel loads.
2026-10-11 18:13:30 +09:00
Hannah Lyons 93cb3a1b0d fix(libkernel): compare the full WAIT_UINT value and throw on _umtx_op operation 1 2026-10-11 11:13:09 +02:00
clem-gb 79f90f3d9b feat(libkernel): implement _umtx_op wait and wake operations
Titles that ship their own libc.prx or Unity's PS5Util.prx import
_umtx_op (04AjkP0jO9U) for atomic waits, call_once and futex-style
waits. Implement UMTX_OP_WAIT, UMTX_OP_WAKE, UMTX_OP_WAIT_UINT,
UMTX_OP_WAIT_UINT_PRIVATE and UMTX_OP_WAKE_PRIVATE as FreeBSD 11's
kern_umtx.c does, on the sceKernelSyncOnAddressWait waiter queue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-11 11:13:08 +02:00
Claude c356112f32 fix(libkernel): keep raises off unregistered threads and clamp the handler's MXCSR
Two defects found in review of the Linux delivery:

A raise right after scePthreadCreate reached the new thread before
RunThread set currentThread, so scePthreadSelf() in the handler adopted
a second handle, and could deadlock on glibc's thread lock when the
signal interrupted pthread_getattr_np. The creator now blocks all
signals around the std::thread construction, so the child starts with
them blocked, and RunThread restores the creator's mask once the thread
is registered, as libthr does. A raise in that window stays pending and
is delivered just before the entry runs.

A handler that set reserved MXCSR bits made rt_sigreturn fail with
SIGSEGV. The MXCSR the handler leaves is now masked with the frame's
MXCSR_MASK (0xffbf when it reads 0), as FreeBSD's fpusetregs does, on
both platforms; Windows also keeps CONTEXT.MxCsr equal to
FltSave.MxCsr.

guest_raise_exception raises right after each of 50 thread creations and
checks scePthreadSelf() in the handler, and its context round trip sets
a reserved MXCSR bit and FZ and checks that only FZ is kept.

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwJx7AHrSUaMGSpEGhL1Kb
2026-10-11 11:12:02 +02:00
Adrià 90c152e840
Merge pull request #1333 from TibixDev/pr/descriptor-pool-recycling
perf(agc): recycle descriptor pools after their last set is released
2026-10-11 11:11:24 +02:00
Claude dca5a88ef2 feat(libkernel): deliver sceKernelRaiseException on Linux
sceKernelRaiseException threw on Linux, so a title whose garbage
collector stops threads with it (Unity's PS5Util raises SIGUSR1 on each
thread and reads mc_rsp from the handler's context) could not run there.

The raise now sends the host SIGUSR1 to the target thread with
pthread_kill. The host handler, installed on first use with SA_SIGINFO
and SA_RESTART, builds the FreeBSD-layout ucontext from the interrupted
registers and the FXSAVE area, calls the guest handler on the target's
own stack and writes the registers back, so the handler's changes reach
the interrupted code, as they do on Windows. errno is left as the
handler leaves it, as libthr does.

A raise on another thread takes the target's join lock with the host
signal blocked and returns ESRCH once the thread has finished, so a
detached thread's pthread_t is never signalled after it exits. The
pthread_t is recorded when the thread is created or adopted. Handlers
are now lock-free atomics, as the host handler reads them.

guest_raise_exception now runs on every platform. It also checks that
r13 and xmm8 reach the handler and that r12 and xmm8 written by the
handler reach the interrupted code.

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwJx7AHrSUaMGSpEGhL1Kb
2026-10-11 11:11:23 +02:00
Adrià Franch a0e03ab48d fix(agc): write a color compare's channels to their own registers 2026-10-11 11:10:41 +02:00
Adrià Franch 6ac5cad133 fix(agc): compare the red channel of a swizzled view 2026-10-11 11:10:41 +02:00
Gjon Gojcevic d32a7881f0 feat(agc): apply the view's channel selects to a color compare
Comparison sampling of a color texture required the view's X channel to select red. A title runs image_sample_c_lz on a 1x1 R8 unorm placeholder whose dst_sel is constant 0 on all four channels.

On hardware the compare result is placed in every channel and each returned channel then applies its own dst_sel: 0 gives 0, 1 gives 1, R/G/B/A give the compare result. Return each dmask register from its own select, and throw only for the reserved selects 2 and 3.
2026-10-11 11:10:41 +02:00
Adrià Franch 3ac63a6d4a fix(libc): key the .eh_frame index on the image, drop the VirtualQuery fallback, test unwinding through runtime DLLs
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:09:18 +02:00
Gjon Gojcevic 2122d7f308 perf(libc): index .eh_frame and find unwind modules without a syscall
On Windows every unwind step called VirtualQuery to find the frame's
module, and a module with a plain .eh_frame (libstdc++, libgcc, libwinpthread)
was searched by decoding each FDE in turn. A C++ exception crossing those
frames cost about a millisecond. Look the module up with RtlPcToFileHeader
first, falling back to VirtualQuery for images the loader does not know,
and binary-search a per-module index of FDE start addresses built on first
use.
2026-10-11 11:09:12 +02:00
Adrià Franch 60a14b5be6 fix(recompiler): bind a 2D texture to a 1D image access
A 1D sample or load of a 2D T# had no runtime image mode after the mode table landed, so it was still refused at materialization. Sampled 1D accesses now also accept a 2D view; the address completion in the emitter reads the missing row as 0.
2026-10-11 11:07:41 +02:00
Gjon Gojcevic 8f44aa656a fix(recompiler): read sampled image address components the instruction omits as 0
Measured on hardware: a position component the instruction omits reads as 0, like an explicit 0, and the next VGPR is ignored. Missing array layers and derivative components are 0 too. Cube coordinates still need all components.
2026-10-11 11:07:41 +02:00
Adrià Franch ac1c3b775b fix(agc): read the base level of a mipmapped view through unnormalized coordinates only where the hardware does
Multi-level views, and views starting above mip 0, are bound as their base
level only when every use of the image is image_sample_lz through an
unnormalized S# without minimum LOD or LOD bias, the case measured exact on
RDNA2. Selected-LOD, implicit-LOD and offset uses keep throwing.

The recompiler records selected-LOD uses (SamplerUseNonZeroLod) and proves
the case per image (imageUnnormalizedBaseLevel); the shader disk cache
format goes to 27.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:07:25 +02:00
Gjon Gojcevic 0fe4d66b7e fix(agc): sample the base level of mipmapped views with unnormalized coordinates
Vulkan only accepts unnormalized samplers on single-level views, while the
guest binds full mip chains and samples their base level. Bind a lazily
created one-level view of the descriptor's base mip instead of refusing
mipmapped views and views that start above mip 0.
2026-10-11 11:07:25 +02:00
Adrià ac2c5c08c8
Merge pull request #1349 from TibixDev/pr/rgba16-component-order
fix(agc): support alternate channel order in 16-bit color targets
2026-10-11 11:07:22 +02:00
Adrià Franch 3c8c02f194 docs(debt): move the PPSA01530 imports line into Unknown function info and note the inferred Ult forwards 2026-10-11 11:07:12 +02:00
Achraf Reyani c9f4689248 fix(exports): drop the sceNpWebApi2GetMemoryPoolStats stub and register the test with the shared guest tests
include from Equeue.cpp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:07:03 +02:00
xXPBSXx c60c123f37 fix(libScePad): export scePadUnknown_n3kSX62fgNo under its NID
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 11:07:03 +02:00
xXPBSXx c4d29f6a99 fix(exports): export the calls PPSA01530, PPSA23827 and PPSA13356 import
Forwards _sceUltWaitingQueueResourcePoolCreate and _sceUltSemaphoreCreate to the existing calls, like the other underscore Ult exports. Declares sceNetShowIfconfig, sceNpWebApi2GetMemoryPoolStats, Json::Value::setNullAccessCallBack, kqueue, kevent and one pad call of unknown name without an implementation.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 11:07:03 +02:00
Karan Vora 17267336af fix(shader): get the pknorm tie error from exact subtractions
normF32 took the error of p = |x| * scale from fma(|x|, scale, -p).
Vulkan only guarantees GLSL Fma on f32 the precision of a multiply
followed by an add, and lavapipe in Mesa 25.2.8 splits it, so the error
was 0 there and products that round to k + 0.5 were resolved by
roundEven: v_cvt_pknorm_u16_f32 of 0x37c000c0 gave 0x00020002 instead of
0x00010001.

scale + 1 is a power of two, so A = |x| * (scale + 1) is exact and the
product is A - |x|. Since A >= |x|, p = A - |x| and the error
(A - p) - |x| are computed with correctly rounded subtractions only
(Fast2Sum), which every driver gives exactly.
2026-10-11 05:03:58 -04:00
Adrià a0165d6774
Merge pull request #1307 from ebarr24/codex/luna-posix-file-errors
fix(libkernel): translate scalar POSIX I/O errors
2026-10-11 11:03:50 +02:00
Adrià 4f8d4017c7
Merge pull request #1296 from TibixDev/pr/pad-file-input
feat(pad): accept timed controller pulses from a local command file
2026-10-11 11:01:22 +02:00
Adrià Franch de89b88900 test(agc): expect the reversed-order blend rejection by its message 2026-10-11 10:59:37 +02:00
TibixDev 058b7e8f94 fix(agc): support alternate channel order in 16-bit color targets
Map red and blue exports, write masks and constant-color blend factors together. Reject conflicting simultaneous target constants.

Semantics: Mesa 26.2.2 src/amd/common/ac_formats.c ac_translate_colorswap; console equivalence remains unverified. Graphics tests passed. Written with AI assistance.
2026-10-11 10:59:37 +02:00
Karan Vora e0be950774 perf(shader): pick f16 min, max and med3 results on the bits
v_min_f16, v_max_f16, v_min3_f16, v_max3_f16, v_med3_f16, v_pk_min_f16
and v_pk_max_f16 converted their sources to f32, ran the f32 min, max
or med3 with its NaN and signed-zero rules, and converted the result
back to f16 before applying the f16 NaN rules on the bits. The result
is always one of the sources, or for two zeros their sign bits
combined, so it is now chosen on the f16 bits: an integer comparison of
the bits with the sign folded into an ordering key, the same AND/OR
rule for two zeros, then the existing NaN, IEEE_MODE, denormal flush
and clamp rules.

The integer comparison doesn't depend on how the driver converts f16
denormals to f32. Comparing the f32 conversions instead fails on an
Intel UHD, whose UnpackHalf2x16 makes f16 denormals zero when the
module declares no f16 DenormPreserve, as these instructions no longer
convert to f16.

New test agc_driver_float16_min_max_bits checks the seven instructions
(VOP2 and VOP3 forms with abs, neg, op_sel and clamp; packed op_sel,
op_sel_hi and neg) on random and special inputs against a model of
those rules, in seven float modes including the f16 input denormal
flush. Current main gives the same results as the model on an RTX
4060, an Intel UHD and lavapipe.
2026-10-11 04:59:08 -04:00
Hussein Kadhim 14446548a9 fix(libkernel): keep mkdir errno stable and handle trailing separators in sceKernelMkdir
Capture errno before the ENOTDIR lookup, translate EINVAL from a name
under a regular file to ENOTDIR, check the parent only once and strip a
trailing separator before taking it, and split the dense rmdir return.
2026-10-11 10:58:38 +02:00
Hussein Kadhim e4b6a7b919 fix(libkernel): report ENOTDIR from mkdir and rmdir when a path component is a file
On Windows mkdir_nid_postfix returned ENOENT and sceKernelMkdir and
sceKernelRmdir returned ENOENT or EIO when a regular file was used as a
directory in the path. FreeBSD mkdir(2) and rmdir(2) return ENOTDIR for
a path component that is not a directory.
2026-10-11 10:58:21 +02:00
Karan Vora 2069fd1262 Merge remote-tracking branch 'origin/main' into perf/shader-coherent-alias 2026-10-11 04:57:31 -04:00
Adrià fd50c632a9
Merge pull request #690 from nicolasabosch/docs/doom-homebrew-compatibility
docs: record DOOM homebrew integration compatibility
2026-10-11 10:57:13 +02:00
Karan Vora 8d0a0504ae Merge remote-tracking branch 'origin/main' into perf/shader-pack-conversions-f32 2026-10-11 04:57:04 -04:00
Adrià Franch bd79dd4898 test(agc): register the descriptor pool recycling test in ctest 2026-10-11 10:54:58 +02:00
TibixDev e645d13048 test(agc): install the guest terminate handler for pool failures 2026-10-11 10:54:52 +02:00
TibixDev 4e7ca3c760 fix(agc): recycle descriptor pools after their last set is released
Allocate cached sets without individual-free pools. Reset a pool after its
last owner releases it. Keep stable pool indices, skip full pools, and
terminate if reset fails. No GPU wait is added.

This avoids RADV 26.2.2's affected individual-free allocation path.

Validation: Fedora 44 Release graphics tests pass. The reset-failure
regression fails on the previous behavior and passes on this change.
llvmpipe and RX 6600 pass the 3,301-set lifecycle test with core and
synchronization validation. Windows was not tested.

AI-assisted: yes.
2026-10-11 10:54:44 +02:00
Hussein Kadhim 1100d41a36 fix(kernel): accept the default handler for SIGKILL and SIGSTOP in signal
FreeBSD's kernel_sigaction rejects SIGKILL and SIGSTOP only for a handler other than SIG_DFL, so signal(9, SIG_DFL) and signal(17, SIG_DFL) succeed. Drop the SIG_ERR rejection, which has no kernel basis and which sigaction does not apply.
2026-10-11 10:54:27 +02:00
TibixDev 3a35841aad feat(pad): accept timed controller pulses from a local command file
Add an optional input helper for test runs without desktop input injection. Preserve physical input and release injected buttons automatically.

Validation: guest_pad tests and Python helper CLI smoke checks passed. Written with AI assistance.
2026-10-11 10:54:18 +02:00
Hussein Kadhim a8cc561f82 fix(libkernel): accept signal() for every valid signal number
signal() returned SIG_ERR with EINVAL for any signal without a host
equivalent, such as SIGHUP, SIGPIPE and SIGUSR1, while sigaction()
accepted them. FreeBSD's signal() is sigaction() with SA_RESTART and fails
only for numbers outside 1..128 and for SIGKILL and SIGSTOP.
2026-10-11 10:53:09 +02:00
Adrià 1c75f4d228
Merge pull request #3357 from AchrafReyani/fix/spirv-unordered-compare-nvidia
fix(shader): emit unordered f32 relations as negated ordered ones
2026-10-11 10:52:35 +02:00
Adrià Franch ba46784e16 test(libkernel): pin direct sceKernelRead/Write/Lseek errors and a read on a directory 2026-10-11 10:51:03 +02:00
Adrià 85c7cf9b02
Merge pull request #3343 from AchrafReyani/carry/progress-literal-braces
fix(progress): ignore braces in literals and comments when scanning bodies
2026-10-11 10:50:56 +02:00
Ethan Barr 79baad41f4 fix(libkernel): translate scalar POSIX I/O errors 2026-10-11 10:50:48 +02:00
Adrià 3c3992c5c2
Merge pull request #2985 from MrMha/fix/wait-memory-timeout-2832
fix(agc): keep polling unsatisfied memory waits after diagnostics
2026-10-11 10:50:34 +02:00
Adrià 536cbf4a98
Merge pull request #3341 from AchrafReyani/carry/shareplay-connection-info
fix(libSceSharePlay): export sceSharePlayGetCurrentConnectionInfoA with no Share Play session
2026-10-11 10:49:50 +02:00
Adrià c166694df6
Merge pull request #3352 from babyhuey/feat/libkernel-getppid
feat(libkernel): implement getppid
2026-10-11 10:49:46 +02:00
Adrià 7feed2748a
Merge pull request #1076 from TideOPL/fix/pad-read-debt-note
fix(libScePad): queue input states for scePadRead
2026-10-11 10:49:44 +02:00
Adrià f38dc53d0f
Merge pull request #3347 from overlordxrz-source/feat/libc-getprogname
feat(libSceLibcInternal): implement getprogname
2026-10-11 10:49:27 +02:00
Adrià 3fb2e29d75
Merge pull request #3315 from pushkarreddyy/feat/libc-nan
feat(libc): implement nan and nanf
2026-10-11 10:49:06 +02:00
Adrià d5477f8402
Merge pull request #2015 from arvindfroi/fix/agc-placeholder-images
fix(agc): typed image heaps on devices without nullDescriptor
2026-10-11 10:48:40 +02:00
Adrià f6b421b73c
Merge pull request #3040 from CouchRiv/fix-shader-ldexp-f16-denorm-flush
fix(shader): flush v_ldexp_f16 denormals per the f16 denormal mode
2026-10-11 10:48:14 +02:00
Adrià Franch 0efa96271c docs: update DOOM homebrew compatibility with merged dependencies and third-party results
Drops the stale pending-dependency note (#553 #683 #684 #685 are merged), adds the
package source and the Linux, extended-gameplay, save/load and audio results
reported in the thread, and replaces the cold-start note with the measured cause.
The UCRT diagnostic note is removed: no report on current main.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 10:47:25 +02:00
Nicolas Abosch 63ddfcbb51 docs: record DOOM homebrew integration compatibility 2026-10-11 10:47:11 +02:00
Adrià d3e84f8543
Merge pull request #3296 from SynnZer0/feat/npwebapi2-memory-pool-stats
feat(libSceNpWebApi2): implement sceNpWebApi2GetMemoryPoolStats
2026-10-11 10:46:44 +02:00
Adrià 71dda5b333
Merge pull request #3297 from SynnZer0/fix/libkernel-module-info-st-size
fix(libkernel): ignore the input st_size of sceKernelGetModuleInfoFromAddr
2026-10-11 10:45:21 +02:00
Adrià 80ee1191d3
Merge pull request #1334 from TibixDev/pr/draw-descriptor-metadata
perf(agc): write draw descriptors from retained CPU metadata
2026-10-11 10:45:19 +02:00
Adrià 097a6288f1
Merge pull request #3130 from fma-rc/fix/strerror-r-unknown-short
fix(libc): keep EINVAL from strerror_r for an unknown error with a short buffer
2026-10-11 10:44:49 +02:00
Adrià cb052ff0b8
Merge pull request #2212 from exefer/fix/relinker-linux-declared-binding
fix(relinker): bind Linux guest imports by declared module identity
2026-10-11 10:44:27 +02:00
Hussein Kadhim d67ad1fc14 docs(technical-debt): record the Linux narrow %p difference 2026-10-11 10:43:41 +02:00
Hussein Kadhim 44f00e2be8 fix(libc): format %p as FreeBSD does on Windows
The Windows formatter passed %p to the host CRT, which prints 16
zero-padded digits without a prefix. FreeBSD prints 0x followed by the
lowercase hex digits (0x0 for a null pointer), as if by %#lx.
2026-10-11 10:43:41 +02:00
pushkarreddyy 31906bf9b0 feat(libc): implement nan and nanf
Add standard quiet NaN generators nanf (DZU+K1wozGI) and nan (zck+6bVj5pA) to libc.

Resolves startup failure in VLC for PS5 (PPSA85300) where execution halts at nanf on Linux once strsep is available.
2026-10-11 14:12:36 +05:30
SynnZer0 c5bcc085ba feat(libSceNpWebApi2): implement sceNpWebApi2GetMemoryPoolStats
PPSA21703's Unity PSN plugin imports sceNpWebApi2GetMemoryPoolStats
(Xweb+naPZ8Y), so the title did not start.

sceNpWebApi2Initialize now records the pool size of each context and
sceNpWebApi2Terminate forgets it. The statistics report that size with
no peak or current use, as sceHttp2GetMemoryPoolStats does, since nothing
is allocated from the pool. A null output or an unknown context throws.
The signature and layout follow the Http2 statistics and are recorded in
TechnicalDebt.

The library gets its own CMakeLists.txt, equivalent to the generic rule,
to register its test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:42:09 +02:00
Adrià f8d8ae52db
Merge pull request #2532 from hazzardouslysolid/fix/scaled-monotonic-origin
fix(libkernel): initialise scaled clock origin before reading time
2026-10-11 10:41:55 +02:00
Adrià ca898cfcb4
Merge pull request #2531 from hazzardouslysolid/fix/rtc-pre-epoch-timezone
fix(rtc): floor pre-epoch timestamps for timezone lookup
2026-10-11 10:41:17 +02:00
Adrià 4154f0d765
Merge pull request #2411 from karanvora2599/perf/shader-pkrtz-native-rte
perf(shader): convert v_cvt_pkrtz_f16_f32 from the native nearest-even conversion
2026-10-11 10:41:08 +02:00
Adrià 903417e238
Merge pull request #2428 from karanvora2599/perf/shader-dot2-f32-fast-path
perf(shader): compute v_dot2_f32_f16 in f32 outside the special cases
2026-10-11 10:40:42 +02:00
Adrià Franch 364c8936da test(relinker): pin executable import binding to the needed provider 2026-10-11 10:36:00 +02:00
exefer 144b1ea8f8 fix(relinker): bind Linux guest imports by declared module identity 2026-10-11 10:35:55 +02:00
Arvind Frøiland 7216621545 fix(agc): typed image heaps on devices without nullDescriptor
The typed descriptor heaps write a null descriptor for a null guest
image, and the device therefore required VK_EXT_robustness2's
nullDescriptor. MoltenVK has the extension but not the feature, so on
macOS no Vulkan device opened and every GPU test was skipped. The
feature is now enabled when the device has it. Without it, the device
creates a placeholder image per typed image heap: 1x1, cleared to zero,
of the heap's dimension, sample count, numeric class and access, and a
null guest image binds the placeholder of its heap. A heap whose
placeholder the device cannot create throws when a null image reaches
it. TechnicalDebt.md lists where a placeholder differs from a null
descriptor.

agc_placeholder_images checks every image resource the recompiler maps
to a heap against that heap's placeholder, so the two cannot drift
apart, and agc_shader_device_profile now expects a device without
nullDescriptor to be accepted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 10:32:49 +02:00
Achraf Reyani 97ee575d6c fix(shader): emit unordered f32 relations as negated ordered ones
NVIDIA's Vulkan compiler (driver 616.92) aborts while building a pipeline
whose OpFUnordLessThanEqual or OpFUnordGreaterThanEqual compares against
+infinity. The negated inverse ordered relation gives the same result for
every input, NaN included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:32:47 +09:00
Adrià ccf9ff9044
Merge pull request #1922 from rmz-24/feat/libkernel-pthread-getaffinity-np
feat(libkernel): implement pthread_getaffinity_np
2026-10-11 10:32:42 +02:00
Hannah Lyons 0cca339e4b feat(libkernel): implement getppid 2026-10-11 04:30:52 -04:00
Adrià 04ab4a86cd
Merge pull request #921 from 011010/feat/cmake-use-system-deps
build: add ANYPS5_USE_SYSTEM_DEPS option
2026-10-11 10:30:35 +02:00
Adrià 40d50b3f16
Merge pull request #2395 from ArchitDewan/fix/atrac9-gradient-bounds
fix(ajm): reject ATRAC9 gradients beyond decoder bounds
2026-10-11 10:29:27 +02:00
Adrià Franch 1dbf976226 test(agc): snapshot descriptor sets are written whole, without copies
Update descriptorSnapshotTests for the single-update path of this PR.
2026-10-11 10:27:59 +02:00
TibixDev 17cc2ce5b4 perf(agc): write draw descriptors from retained CPU metadata
Replace per-draw Vulkan descriptor copies with a single write from retained buffer and image metadata. Keep per-draw guest snapshots, sets and resource ownership unchanged. Baseline RX 6600 profiling attributed 28% of graphics-worker cycles to descriptor copies.

Validation: mixed descriptor and snapshot regression passes on RADV RX 6600 and llvmpipe with Vulkan validation; graphics and guest-memory tests pass. Written with AI assistance.
2026-10-11 10:27:59 +02:00
Adrià 0c617bae95
Merge pull request #374 from MichonGoddijn231849/fix/depth-htile-fast-clear
fix(agc): depth fast clears through the HTILE metadata
2026-10-11 10:27:15 +02:00
Adrià 7028457e31
Merge pull request #2259 from TheAggie/fix/shader-coherent-bda-atomic-loads
fix(shader): read GLC/DLC BDA dwords with device-scope atomic loads
2026-10-11 10:26:29 +02:00
Adrià 407b5324de
Merge pull request #2373 from 011010/ci/conventions-systemdeps-exemption
ci(conventions): exempt cmake/SystemDeps.cmake from the system-dependency rule
2026-10-11 10:26:03 +02:00
Alex 327bf794a2 docs(shader): flush v_ldexp_f16 results before rounding in the debt entry
The entry said the result is flushed before or after the scale. The
lowering flushes the exact scaled value below the minimum normal before
rounding. Measured on RDNA2 (gfx1036) with round to nearest over every
half magnitude 0x0000..0x0fff of both signs, scaled by 2^-1 and 2^0,
IEEE 0 and 1, denorm16 0..3: no mismatch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 04:24:27 -04:00
Claude b87dd8d845 docs(shader): note the per-bit f16 denormal field against the f32 mode 1 and 2 refusals
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9MzdVqDf6wHUKzNymQSze
2026-10-11 04:24:00 -04:00
Alex 63b2bcb354 fix(shader): flush v_ldexp_f16 denormals per the f16 denormal mode
v_ldexp_f16 ignored the FLOAT_MODE denorm16 flush bits on main. Flush a
denormal half input when bit 0 is clear. When bit 1 is clear, flush the
result when its exact value is below the minimum normal half, decided
on the f32 product before the half conversion rounds it: 0x07ff scaled
by 2^-1 is zero on RDNA2, not the minimum normal. NaN handling and
destination high-half preservation stay the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 04:24:00 -04:00
Adrià 7b5214d429
Merge pull request #846 from merwie/feat/relinker-module-dir
feat(relinker): add --module-dir for modules loaded at run time
2026-10-11 10:23:54 +02:00
Ramzi 45eb492335 feat(libkernel): implement pthread_getaffinity_np
Report the thread's affinity mask as a 32-byte FreeBSD cpuset_t, with
FreeBSD 11's errors: ERANGE for any other set size, ESRCH for a null
thread and EFAULT for a null set.

EVO-PLAYER (PPSA99039 v0.11.0) imports it (Jb2uGFMr688) and calls it
once with a 32-byte set on pthread_self().
2026-10-11 10:23:50 +02:00
Adrià bbd7157150
Merge pull request #822 from Celegans12/feat/agc-unnormalized-sampler-offsets
feat(agc): accept texel offsets with unnormalized sampler coordinates
2026-10-11 10:23:33 +02:00
overlordxrz-source 2806eb57a2 feat(libSceLibcInternal): implement getprogname 2026-10-11 04:22:28 -04:00
Adrià 5c34f9e25e
Merge pull request #3319 from pushkarreddyy/feat/libSceHttp2-ping-interval
feat(libSceHttp2): export sceHttp2WebSocketSetPingInterval
2026-10-11 10:22:11 +02:00
Michon 56ea14f44c fix(agc): an HTILE fill covers a depth surface only over its whole pipe-aligned metadata
A fill was taken to cover the surface when it spanned ceil(w/8)*ceil(h/8)*4 bytes, a linear HTILE layout. In
the pipe-aligned SW_64KB_Z_X layout a surface's HTILE words lie across a 32 KiB metadata block per 1024x512
pixels (AMD PAL gfx10 addrlib: a 16x16 surface has a valid word at offset 260), so a fill of the linear size
cleared tiles it never wrote. HtileMetadataBytes gives that extent; the fast clear tests fill it (the compute
fixture now dispatches one group per KiB with TGID_X).

Reported with a PAL reproducer by @Amoenus.

Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 10:19:53 +02:00
Michon ce65ab251c test(agc): the fast clear tests on main's Mutation::Add gpu flag; one DepthSurface include
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 10:19:53 +02:00
Michon 30a0545b21 fix(agc): a depth surface's clears record on its own device
`Recorder::Active()` is process-wide. With two devices (agc_driver_depth_fast_clear_submit draws on its
own device; its compute-fill DCB makes the driver create a second one, whose recorder becomes the
active one) a surface's fast clear was recorded into the other device's command buffer, unordered with
the draw: the compute-fill case failed about once in 60-90 runs. A surface now records into the active
recorder only when that recorder is its own device's, and submits on its own device otherwise.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 10:19:53 +02:00
Michon c133e23dde fix(agc): depth fast clears through the HTILE metadata
Rebased onto main as one commit (the six commits of #374). A uniform fill over a depth surface's whole
HTILE (DMA_DATA, the fill kernels or a CPU store) clears the depth and stencil aspects its ZMask and
SMem fields say, to DB_DEPTH_CLEAR / DB_STENCIL_CLEAR, when the surface is next bound or sampled.

Main's RADV clear_htile_mask recognition (#2229) now goes through the same pending clear: an HTILE clear
marks the matching surfaces' depth aspect, and one for a surface not created yet is applied when it is
first bound. Main's HTILE address decode and this one are merged into one (TILE_SURFACE_ENABLE, a
nonzero DB_HTILE_DATA_BASE and a depth format).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 10:19:53 +02:00
Adrià Franch abcfa7c23d build: route the Vulkan-Headers include of tests added since the rebase through ANYPS5_VULKAN_HEADERS_INCLUDE_DIR
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 10:18:29 +02:00
husari.orozco 636bfc7298 docs(contributing): document the ANYPS5_USE_SYSTEM_DEPS exception 2026-10-11 10:18:23 +02:00
husari.orozco ce6edc5a00 build: reject an SDL2 without HIDAPI and fall back to shared SPIRV-Tools
A system SDL2 that does not define SDL_JOYSTICK_HIDAPI (sdl2-compat over
SDL3 ships no such macro, and neither does a build with the driver
disabled) fails pad_sdl and makes the disk audio driver open the port
with a different channel count, so ANYPS5_USE_SYSTEM_DEPS=ON now rejects
it with a named error, like the VK_KHR_maintenance8 check. Ubuntu's real
SDL2 defines the macro through its SDL_config.h indirection and is
unaffected.

SPIRV-Tools only exports SPIRV-Tools-static when built with
SPIRV_TOOLS_BUILD_STATIC=ON; distributions that ship it shared expose
SPIRV-Tools instead, so a shared target is aliased to the static name.
2026-10-11 10:18:23 +02:00
husari.orozco 6ad5c61f1a build: route system dependency include paths and pin the shader cache to package versions 2026-10-11 10:18:23 +02:00
husari.orozco 96ad950914 build: add ANYPS5_USE_SYSTEM_DEPS option
Resolve SDL2, freetype, Vulkan-Headers, SPIRV-Headers, glslang and
SPIRV-Tools from the system instead of the bundled submodules when the
option is ON. It is OFF by default, so the bundled build is unchanged.

Every package is required: a missing one, or Vulkan-Headers older than
1.4.310 (the agc driver uses VK_KHR_maintenance8), fails the configure
with an error and nothing falls back to the submodule. The system
packages are exposed under the same target names the bundled path uses,
so the rest of the CMake is untouched.

SDL2 is linked from the system as a shared library because the prx
libraries are shared objects and distribution static SDL2 is usually not
PIC. ffmpeg-core, libjpeg-turbo, stb, VulkanMemoryAllocator and LibAtrac9
stay bundled.
2026-10-11 10:18:10 +02:00
Achraf Reyani ef94a36b90 fix(progress): blank literals and comments in one pass
An apostrophe in a block comment paired with a later character literal on
the same line when literals were blanked before comments, exposing a brace
and ending the body early.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:17:40 +09:00
GalaxyGamingFR f3216874c5 fix(progress): ignore braces in literals and comments when scanning bodies
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 17:16:25 +09:00
Adrià 05c870cc05
Merge pull request #2408 from karanvora2599/perf/shader-compare-constant-flush
perf(shader): fold the denormal flush into f32 compares against constants
2026-10-11 10:14:42 +02:00
Adrià df09e33759
Merge pull request #2407 from karanvora2599/perf/shader-float-to-int-once
perf(shader): saturate f32 to integer conversions once
2026-10-11 10:14:22 +02:00
Abdulrahman Elkordy 0d2eeb87eb fix(libSceSharePlay): fill the connection info with no Share Play session
sceSharePlayGetCurrentConnectionInfoA now writes a 72-byte
SceSharePlayConnectionInfoA that reports no session: status DORMANT,
mode 0, empty online IDs, account IDs 0 and both user IDs invalid (-1).
A null pointer returns SCE_SHARE_PLAY_ERROR_INVALID_ARGS (0x810E0001)
instead of throwing. KytyPS5 and fpPS4 agree on the layout and the error
code; KytyPS5 sets the user IDs to -1, fpPS4 leaves them 0.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 17:14:21 +09:00
xXPBSXx 00fba4472c fix(libSceSharePlay): export sceSharePlayGetCurrentConnectionInfoA
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 17:14:21 +09:00
Merijn 1c6eac425d feat(relinker): add --module-dir for modules loaded at run time
Relinks the ELF modules of extra directories under the module parent directory. Modules the executable or another module needs start with the executable; the others are initialized when the title loads them with sceKernelLoadStartModule, with its start arguments (Windows: __aps5_guest_initialize export; Linux: left out of DT_NEEDED).

Squashed onto main by the reviewer (history had a merge commit).
2026-10-11 10:11:31 +02:00
Celegans12 d0d127b17d feat(agc): accept texel offsets with unnormalized sampler coordinates
Explicit-LOD offset samples through FORCE_UNNORMALIZED samplers now add
sign-extended texel offsets to f32 coordinates before clamping, using
OpFAdd with NoContraction and a sampler specialization selector.

Without native nonconstant-offset support, retain only runtime image
modes valid for unnormalized sampling and reject normalized samplers.
Preserve constant-swizzle handling, indirect-image rejection and main's
flat-volume and flat-line compatibility rules when selecting those modes.

Serialize image compatibility and folding flags and the sampler folding
flag in cache format 34, with roundtrip, preparation and execution coverage.
Retain main's request format 15 and runtime ABI 11.
2026-10-11 10:08:25 +02:00
Adrià f60923bf50
Merge pull request #3294 from kr4y4/feat/shader-compute-user-data-calls
feat(shader): link compute shaders' user-data callees at dispatch
2026-10-11 10:07:22 +02:00
Adrià 6170ce820c
Merge pull request #3167 from CnRJay/perf/agc-sparse-heap-mirror
perf(agc): mirror a sparse descriptor heap instead of copying it per dispatch
2026-10-11 10:07:03 +02:00
Adrià Franch cfb372a035 fix(libSceHttp2): make sceHttp2WebSocketSetPingInterval throw, document under unknown function info
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 10:06:26 +02:00
pushkarreddyy fb2b7b8dce feat(libSceHttp2): export sceHttp2WebSocketSetPingInterval
Export sceHttp2WebSocketSetPingInterval (YfaXPnc8PJE) in libSceHttp2.

Resolves unresolved ELF import in Palworld (PPSA23126, Issue #2648) bundled libdiscord_partner_sdk.prx.
2026-10-11 10:06:05 +02:00
Adrià abdad2a574
Merge pull request #3332 from AchrafReyani/carry/job-manager-test-aligned-alloc
test(libSceJobManager): allocate aligned test blocks without std::aligned_alloc
2026-10-11 10:05:17 +02:00
Adrià 1be0a7ce9b
Merge pull request #3324 from AchrafReyani/carry/host-import-span-windows-alias
fix(agc): import a span's ranges one at a time when Windows refuses its alias
2026-10-11 10:01:20 +02:00
Adrià 5b1c64117d
Merge pull request #3330 from AchrafReyani/carry/agc-ignore-window-offset-enable
fix(agc): ignore the window offset enable bit of the raster mode
2026-10-11 10:00:57 +02:00
Adrià cf0e270a94
Merge pull request #3175 from Raghav314/fix/agc-bda-written-pages
fix(agc): note BDA-written pages at full address width and read back only the claimed ones
2026-10-11 10:00:06 +02:00
Adrià Franch 8c619f16da docs(architecture): user-data callees; drop code comment
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 09:59:27 +02:00
krishnaraya 6d9321fc57 feat(shader): link compute shaders' user-data callees at dispatch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 09:59:27 +02:00
Adrià 59f0269723
Merge pull request #3328 from overlordxrz-source/feat/sharpprospero-sw-version
feat(libs): implement the SharpProspero version queries and export sceSystemServiceLaunchApp
2026-10-11 09:59:15 +02:00
David f65e63fafa test(libSceJobManager): allocate aligned test blocks without std::aligned_alloc
MinGW-w64's UCRT has no aligned_alloc, so the Windows build of
guest_job_manager_tests fails since #3170. Use the aligned operator new
and delete instead, which are standard C++17 on every host.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 16:59:14 +09:00
Adrià e89aabc916
Merge pull request #3326 from AchrafReyani/carry/conventions-silent-stub-section
fix(conventions): restrict silent stub exemptions to their section
2026-10-11 09:58:47 +02:00
Adrià c8facc79ff
Merge pull request #3325 from AchrafReyani/carry/windows-stub-orphan-failed-line
fix(relinker): print the Windows stub's ' -> FAILED' only with dependency diagnostics
2026-10-11 09:58:25 +02:00
Adrià b490b387ef
Merge pull request #3322 from babyhuey/feat/libkernel-creat
feat(libkernel): implement creat
2026-10-11 09:57:47 +02:00
Adrià 3343966239
Merge pull request #3301 from Raghav314/fix/ajm-single-input-in-place
fix(ajm): decode a single input buffer in place instead of copying its stated size
2026-10-11 09:57:23 +02:00
Adrià 5460611fed
Merge pull request #3323 from TheAggie/feat/libkernel-cpuset-setaffinity
feat(libkernel): implement cpuset_setaffinity for the calling thread or process
2026-10-11 09:57:15 +02:00
Adrià 9f051dff35
Merge pull request #3218 from babyhuey/feat/libkernel-sysctl-rng-pseudo
feat(libkernel): support kern.rng_pseudo in sysctlbyname
2026-10-11 09:57:12 +02:00
Adrià a18aaeaa39
Merge pull request #3216 from hugodearaujo/fix/pool-stats-console-errors
fix(net): return the console's errors from the memory pool stats calls
2026-10-11 09:56:52 +02:00
Adrià 832c84298e
Merge pull request #2705 from DariusHQ/fix/windows-guest-libc-placeholders
fix(relinker): skip zero-return guest libc exports for internal libc imports
2026-10-11 09:56:33 +02:00
Adrià 44395d9f95
Merge pull request #3260 from fma-rc/feat/font-writing-line-order
feat(font): order writing line runs by embedding level and report their spacing
2026-10-11 09:55:44 +02:00
Adrià 65313a26ac
Merge pull request #3103 from fma-rc/test/recorder-full-run
test(agc): fix two stale expectations in the full recorder run
2026-10-11 09:55:17 +02:00
Chad 38012ec35c perf(agc): drop a comment the conventions check refuses 2026-10-11 09:55:14 +02:00
Chad b88ad02090 perf(agc): mirror a sparse descriptor heap instead of copying it per dispatch 2026-10-11 09:55:14 +02:00
Adrià 98da5a9267
Merge pull request #3238 from Tamalero/fix/playgo-undeclared-chunks
fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions
2026-10-11 09:54:25 +02:00
Adrià 6a8f0ebb19
Merge pull request #2740 from Yousef13710/fix/content-library-exports
fix(content): export the content calls PPSA06465 imports
2026-10-11 09:53:27 +02:00
Adrià 6cc26ec99b
Merge pull request #2982 from TheAggie/fix/libkernel-mprotect-thread-stack
fix(libkernel): change the protection of guest thread stack pages
2026-10-11 09:52:03 +02:00
Hannah Lyons 04835bdcd1 feat(libkernel): support kern.rng_pseudo in sysctlbyname 2026-10-11 09:51:22 +02:00
Adrià eb15ddc42a
Merge pull request #3041 from CouchRiv/feat-libscesysmodule-get-module-handle-internal
feat(libSceSysmodule): implement sceSysmoduleGetModuleHandleInternal
2026-10-11 09:50:46 +02:00
Adrià c12a19e4de
Merge pull request #3237 from Raghav314/perf/agc-cache-fault-only-resources
perf(agc): cache resources whose only completion work is the fault check
2026-10-11 09:50:44 +02:00
Adrià 51b5f52a9e
Merge pull request #3152 from MarcZX100/codex/marc-select-timeout-range
fix(libkernel): saturate oversized select timeouts
2026-10-11 09:49:58 +02:00
Adrià 8ee2834a38
Merge pull request #2945 from MarcZX100/carry/libkernel-system-sw-version
feat(libkernel): implement sceKernelGetSystemSwVersion
2026-10-11 09:49:38 +02:00
hugodearaujo 7e5a34c58c fix(net): return the console's errors from the memory pool stats calls
Measured on a PS5 (firmware 13.60):
- sceSslGetMemoryPoolStats returns 0x8095F007 for a null output, before
  the id check, and 0x8095F006 for an unknown or terminated context,
  zeroing the 32-byte output.
- sceHttp2GetMemoryPoolStats returns 0x817B1225 for a null output,
  before the id check, and 0x817B1100 for an unknown or terminated
  context, zeroing the 32-byte output.
- sceNetGetMemoryPoolStats checks the pool before the output, so an
  unknown pool with a null output returns EBADF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:49:13 +02:00
fma-rc 433302be58
test(agc): check the recorder's (s) and (w) generations around the storage image's own import 2026-10-11 09:49:13 +02:00
fma-rc 3bb39589f3
test(agc): fix two stale expectations in the full recorder run 2026-10-11 09:49:13 +02:00
Adrià 65a4e8ef34
Merge pull request #2842 from Get-fix/fix/libc-daemon
fix(libc): export daemon
2026-10-11 09:49:05 +02:00
overlordxrz-source aaf5754d27 feat(libSceSystemService): export sceSystemServiceLaunchApp
AI-assisted: yes
2026-10-11 03:48:47 -04:00
overlordxrz-source aeee59614e feat(libkernel): implement sceKernelGetAllowedSdkVersionOnSystem
AI-assisted: yes
2026-10-11 03:48:47 -04:00
overlordxrz-source 26cad4e8c8 feat(libkernel): implement sceKernelGetProsperoSystemSwVersion
AI-assisted: yes
2026-10-11 03:48:46 -04:00
Achraf Reyani 94d6a82d83 docs(debt): list sceAudioInInit with the silent stubs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:46:16 +09:00
Scott Schuster eb33094e20 test(shader): register the cross-workgroup test block as GPU-accessible
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:46:00 -05:00
Blazing Cook 271e31a5a3 fix(conventions): restrict silent stub exemptions to their section 2026-10-11 16:45:35 +09:00
Adrià Franch db3c429e42 docs(playgo): update chunk-set comment and record unchecked chunk ids in TechnicalDebt
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 09:44:17 +02:00
Cesar Rodriguez 082177e1b7 fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions
PS5 dumps carry no playgo-chunkdefs.xml (only sce_sys/playgo-scenario.json, which
lists no chunks), so the valid set fell back to chunk 0 and every query for another
chunk returned SCE_PLAYGO_ERROR_BAD_CHUNK_ID. A title that asks for all of its chunks
in one scePlayGoGetLocus call then never sees them as installed and waits forever.

Without definitions the chunk table is unknown and a dump is fully installed, so any
chunk id is accepted and reported as local. With playgo-chunkdefs.xml present,
validation is unchanged. scePlayGoGetChunkId still reports the known set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:44:13 +02:00
Adrià 2a4e03ce58
Merge pull request #3151 from MarcZX100/codex/marc-socket-positioned-io
fix(libkernel): return ESPIPE for positioned socket I/O
2026-10-11 09:43:15 +02:00
Adrià Franch 1583126a35 docs(libkernel): record unverified sceKernelGetSystemSwVersion argument checks 2026-10-11 09:43:06 +02:00
MarcZX100 d8ba169df8 fix(libkernel): correct system version ABI layout 2026-10-11 09:43:02 +02:00
MarcZX100 e0e0b66cbb docs(libkernel): clarify system version ABI assumption 2026-10-11 09:42:57 +02:00
pushkarreddyy cbacc46ede fix(libkernel): return SCE_KERNEL_ERROR codes in sceKernelGetSystemSwVersion 2026-10-11 09:42:49 +02:00
pushkarreddyy 5890160278 feat(libkernel): implement sceKernelGetSystemSwVersion
(cherry picked from commit 7143d0b46e389254b0b3bd52812a196ace0c7a6b)
2026-10-11 09:42:49 +02:00
fma-rc 5680c32381
fix(font): throw where the writing line error codes come from the PS4 module only and accept attribute 0 2026-10-11 09:41:52 +02:00
Achraf Reyani 62d6cbe42d test(relinker): check that a Windows load failure starts with its own message
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:41:25 +09:00
Scott Schuster 73e0890c20 fix(shader): read GLC/DLC BDA dwords with device-scope atomic loads
Coherent (GLC/DLC) global loads were emitted as Volatile loads through
physical pointers. Volatile does not make another workgroup's stores
visible within the same dispatch, so a workgroup spinning on a flag
written by another one (decoupled look-back scans, as in RADV's
acceleration-structure build) never saw it on NVIDIA. Aligned coherent
dword reads now use OpAtomicLoad at device scope; the byte path keeps
the old reads for unaligned addresses.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:41:19 -05:00
Badr d102e186c9 fix(relinker): print the Windows stub's ' -> FAILED' only with dependency diagnostics 2026-10-11 16:40:50 +09:00
Get-fix 520b9facb6 fix(libc): export daemon
VLC (PPSA85300) imports daemon (Wn6I3wVATUE) and fails to load because
no library exports it. Forking into the background is not supported,
so it throws if called. VLC 3.0 calls daemon only when its daemon
option is set, and the title starts libVLC with --ignore-config and
without --daemon.
2026-10-11 09:40:35 +02:00
MarcZX100 4b3f02ab13 docs(libkernel): clarify guest socket descriptor range 2026-10-11 09:36:43 +02:00
MarcZX100 bb9bd2183c fix(libkernel): return ESPIPE for positioned socket I/O 2026-10-11 09:36:43 +02:00
Adrià 2bb78d2c7a
Merge pull request #1825 from TheAggie/feat/agc-ngg-vertex-mesh-v2
feat(agc): run unregistered NGG vertex programs that need a workgroup on the mesh path
2026-10-11 09:35:19 +02:00
Adrià a4b0b16bb8
Merge pull request #3244 from leorossi2005/feat/appcontent-download-progress
feat(libSceAppContent): implement sceAppContentGetAddcontDownloadProgress
2026-10-11 09:33:12 +02:00
Adrià a6d45b68fa
Merge pull request #3170 from fma-rc/feat/libscejobmanager-cpu
feat(libSceJobManager): implement CPU job sequences
2026-10-11 09:32:50 +02:00
Adrià 3db4637fcc
Merge pull request #2789 from tototomate123/fix/hfw-apr-split
fix(APR): correct guest resolution outputs, object layout and gather sizing
2026-10-11 09:32:21 +02:00
Adrià 683bb1c78c
Merge pull request #2788 from tototomate123/fix/hfw-http-split
fix(libSceHttp): retain request-status callbacks with the guest ABI
2026-10-11 09:32:00 +02:00
Scott Schuster bb4b938e34 feat(libkernel): implement cpuset_setaffinity for the calling thread or process
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:31:57 -05:00
Hannah Lyons 01ed49c98e feat(libkernel): implement creat 2026-10-11 03:31:04 -04:00
raghav314 29c0814c90 fix(ajm): an Opus run stops before the next packet once the output has no room for its frame
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:00:50 +05:30
raghav314 26bd36df84 fix(ajm): decode a single input buffer in place instead of copying its stated size
A job's inputs were joined into one vector before decoding, copying every
input buffer at its stated size. PPSA36082's FMOD submits Opus run jobs
whose one input buffer states 0xFFFFFE74 bytes (a remaining size that
went below zero) ahead of a single packet, so each such job copied about
4 GiB and sceAjmBatchStart took about a second; the mixer missed its
deadline and the title pushed silence. A job with one input buffer now
decodes from that buffer in place, reading only the packets it decodes;
jobs with several input buffers are joined as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:00:50 +05:30
Adrià b6f649d962
Merge pull request #3286 from kr4y4/fix/agc-test-flat-apertures-int64-atomics
test(agc): skip flat aperture 64-bit atomic rows without shaderBufferInt64Atomics
2026-10-11 09:29:16 +02:00
Adrià bd06925906
Merge pull request #3314 from AchrafReyani/feat/libc-fabs-trunc-fma
feat(libc): implement fabs, trunc and fma
2026-10-11 09:28:25 +02:00
Adrià 92bc441279
Merge pull request #3306 from CouchRiv/fix-shader-ldexp-f32-denorm-keep
fix(shader): keep f32 subnormals in v_ldexp_f32 when denormals are kept
2026-10-11 09:28:17 +02:00
Adrià 74807ef113
Merge pull request #3305 from CouchRiv/feat-libscevideoout-delete-output-mode-event
feat(videoout): implement sceVideoOutDeleteOutputModeEvent
2026-10-11 09:28:09 +02:00
Alex f1af6683a1 fix(libSceSysmodule): open host modules only through libs/<name>.prx
Drop the retry on <name>.prx after libs/<name>.prx fails. The test now
runs from its own directory holding libs/libSceFiber.prx, copied from
the libSceFiber output, so the single path resolves in the test too.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 03:28:05 -04:00
Scott Schuster f38408ef5c fix(libkernel): keep stack protection inside the stack and never throw while restoring it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:28:03 -05:00
Scott Schuster 24ae0a98d0 fix(libkernel): check the requested stack range and restore guard pages at thread exit
A stack base need not be page aligned (it is not on Linux), so rounding the
range down first could leave the stack and miss the stack path. The range the
guest asked for is now checked against the guest stack, and the rounded
pages are protected, as FreeBSD rounds the address down.

A thread that exits with part of its stack protected left those pages to the
next thread that reused the stack. Protected stack pages are recorded, and a
thread's stack is made readable and writable again when it is unregistered at
exit.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:28:03 -05:00
Scott Schuster 67bccf6dd4 fix(libkernel): change the protection of guest thread stack pages
On Windows a guest thread runs on its host thread's stack, which is not a
registered guest allocation, so mprotect on any of its pages failed with
EINVAL. A guest that guards the bottom of its own stack (Dolphin's JIT
read-protects 64 KiB there to catch stack overflows) got an error where the
PS5 changes the protection.

A range that lies inside a live guest thread stack, with no GPU access
requested, now takes the native protection directly. Ranges that cross the
stack's bounds are still rejected.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:28:03 -05:00
Claude 3bfb0445e5 fix(libSceSysmodule): link and run guest_sysmodule_tests like the other guest tests
Link libc, configure Windows unwinding for the test so its runtime_error
checks are caught, and run it from libSceFiber's output directory so
openHostModule finds the unpatched libSceFiber.prx next to the modules the
test already loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9MzdVqDf6wHUKzNymQSze
2026-10-11 03:27:59 -04:00
Alex 19dc22b010 feat(libSceSysmodule): implement sceSysmoduleGetModuleHandleInternal
Return a host module handle for a loaded sysmodule id so callers can
sceKernelDlsym after sceSysmoduleLoadModule. Unknown or null inputs
throw like neighbouring internal load paths; unloaded ids return
0x805A1001. Unblocks Prospero Win past NID D8cuU4d72xM at load.

Co-Authored-By: Composer <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 03:27:52 -04:00
Adrià 5c7ceb07b0
Merge pull request #3292 from AchrafReyani/carry/libkernel-available-direct-memory-largest-block
fix(libkernel): report the largest free direct memory block from sceKernelAvailableDirectMemorySize
2026-10-11 09:27:09 +02:00
Adrià 74a0ba3965
Merge pull request #2479 from NahuelGenchi/fix/agc-alias-one-slice-array
perf(agc): take a 2D storage image's results for a one-slice array on the device
2026-10-11 09:27:06 +02:00
Adrià 66479c96d0
Merge pull request #3281 from oneandonlydean/up4/amm-placement-3146
fix(libkernel): reserve the AMM virtual address ranges at the top of the guest arena
2026-10-11 09:27:00 +02:00
Adrià 8accbdaee0
Merge pull request #3287 from AchrafReyani/carry/conventions-comment-apostrophes
fix(tools): keep apostrophes in comments from opening character literals
2026-10-11 09:26:31 +02:00
Adrià cfcffebd0f
Merge pull request #3290 from AchrafReyani/carry/relinker-windows-tls-thread-pointer
fix(relinker): place the Windows thread pointer after the TLS size rounded to its own alignment
2026-10-11 09:26:24 +02:00
Adrià f0d15c3d81
Merge pull request #3261 from MarcZX100/codex/libc-dirname-ppsA99764
feat(libc): implement dirname
2026-10-11 09:25:39 +02:00
Adrià 8975b59980
Merge pull request #3188 from gookie-dev/perf/agc-initial-context-registers-once
perf(agc): build the initial context registers once
2026-10-11 09:25:11 +02:00
Adrià fbcdf1a804
Merge pull request #2992 from CnRJay/fix/agc-sparse-heap-cut
fix(agc): copy a sparse descriptor heap only up to its last backed byte
2026-10-11 09:24:32 +02:00
Abdulrahman Elkordy aa653ec50e fix(agc): import a span's ranges one at a time when Windows refuses its alias
#3158 imports a run of address-adjacent registered ranges as one span.
On Windows a shared mapping in the span needs a read-write alias, and
MapAlias refuses one unless the range is a single contiguous run of
views of one section. Ranges that are adjacent in guest address can be
separate views, so the refusal escaped from importAllocation and
agc_driver_dcc_keys_first_write failed on main with "read-write alias
of shared guest memory ...: the range is not one contiguous run of
views of a section".

A span whose alias is refused is now remembered, and its ranges are
imported one at a time as before spans; a single range that is refused
still throws.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
2026-10-11 10:24:24 +03:00
Adrià 5a9c61a9c0
Merge pull request #3239 from Tamalero/fix/agc-null-indirect-base
fix(libSceAgc): accept a null base in sceAgcDcbSetBaseIndirectArgs
2026-10-11 09:24:07 +02:00
raghav314 ef3a381824 test(agc): flat store stamped blocks skip when host imports are compared, not watched
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:54:02 +05:30
raghav314 c0348a02bf fix(agc): note BDA-written pages at full address width and read back only the claimed ones
A shader store through the BDA table records its 4 KiB page in the fault
buffer, and the driver marks those pages written after the use. The page
number was truncated to 32 bits, so a store above 16 TiB marked a page at
another address. And the driver scanned all 4096 slots after every use,
even when nothing was stored.

Slots now hold a 128 KiB chunk (its number plus one, 32 bits for any
address below 512 TiB) and a mask of its 4 KiB pages. A shader that
claims a slot appends it to a list, with a count. The driver reads the
count, decodes only the claimed slots, marks each run of pages once and
clears only those slots. A writable BDA range past 512 TiB is refused
when the table is built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:54:02 +05:30
Adrià 6968564656
Merge pull request #2790 from tototomate123/fix/hfw-shader-split
fix(shader): evaluate signed minimum in runtime SRT expressions
2026-10-11 09:23:58 +02:00
xXPBSXx 1fb359b959 fix(content): export the content calls PPSA06465 imports
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 09:23:39 +02:00
Adrià ecd82056fa
Merge pull request #3189 from gookie-dev/perf/ngs2-parse-waveform-file-headers
perf(libSceNgs2.native): parse waveform files without reading their s…
2026-10-11 09:23:30 +02:00
Adrià 4484ddc0bf
Merge pull request #3105 from parl0v/feat/np-get-sandbox-info
docs(npmanager): name ZVZ++68nNI8 sceNpGetSandboxInfo, imported by PPSA28416
2026-10-11 09:23:05 +02:00
Adrià ccb299cbca
Merge pull request #2756 from TheAggie/feat/agc-radv-vkquake-dispatch
feat(agc): accept the dispatch and indirect packet forms vkQuake's RADV emits
2026-10-11 09:22:58 +02:00
Adrià be8a67db1c
Merge pull request #3228 from GustavoGamarra95/feat/agc-alpha-to-coverage
feat(agc): emulate undithered alpha-to-coverage
2026-10-11 09:22:23 +02:00
Adrià 386cf26fc7
Merge pull request #3066 from MarcZX100/codex/libc-lround-range-3045
fix(libc): match FreeBSD lround errors on Windows
2026-10-11 09:21:54 +02:00
Adrià 47c8e19eb7
Merge pull request #1619 from fisherjoey/fix/depth-compare-copy
perf(agc): sample comparison-read R32F/R16 surfaces from a GPU depth copy of their storage image
2026-10-11 09:21:23 +02:00
Adrià 6957bb4ae2
Merge pull request #2785 from tototomate123/fix/hfw-relinker-split
fix(relinker): preserve Linux executable exports and ELF section addresses
2026-10-11 09:20:45 +02:00
Adrià df23cab62b
Merge pull request #3211 from Scramblrrrr/codex/recorder-buffer-only-budget-main
fix(agc): enforce the kept-byte budget before buffer-only work
2026-10-11 09:20:12 +02:00
DariusHQ e720d3cd61 fix(relinker): skip zero-return guest libc exports for internal libc imports
Since #1454, a libSceLibcInternal import that no native library exports
on Windows falls back to the title's own libc.prx. The loader shim that
ps5-native-app-boilerplate builds into homebrew titles exports 1874
functions at three addresses whose code is `xor eax, eax; ret` or
`pxor xmm0, xmm0; xor eax, eax; ret`. Such an import then binds to a
function that returns 0, and the title starts instead of stopping with
`unresolved ELF import`.

The Windows guest module writer records the exported functions whose
code is one of these two sequences, and the entry stub leaves the guest
libc.prx out of the search for those names. A guest export with code of
its own still provides a missing libSceLibcInternal function, and native
libraries keep their priority.
2026-10-11 09:20:00 +02:00
Adrià effc61e4cd
Merge pull request #2787 from tototomate123/fix/hfw-filesystem-split
fix(libkernel): return guest chmod errors and implement sceKernelFutimes
2026-10-11 09:19:44 +02:00
Adrià 840fb0f574
Merge pull request #3279 from oneandonlydean/carry/alx-ancillary-masked-lanes
fix(shader): prove masked lanes unread across exec phis, loops and image operations
2026-10-11 09:19:40 +02:00
Adrià c757e8eaa7
Merge pull request #3220 from kr4y4/fix/agc-sampler-border-color-class
fix(agc): pick float or integer sampler border colours from the paired images
2026-10-11 09:19:14 +02:00
Adrià 0c63c83882
Merge pull request #3227 from GustavoGamarra95/perf/unwind-info-procmap-query
perf(libkernel): look up unwind mappings with PROCMAP_QUERY
2026-10-11 09:18:50 +02:00
Adrià 379e5d8795
Merge pull request #3280 from MarcZX100/codex/libc-memset-s-freebsd-3166
fix(libc): follow FreeBSD memset_s errors
2026-10-11 09:18:14 +02:00
Adrià 5b5220ccfd
Merge pull request #3276 from MarcZX100/codex/test-filesystem-native-error-3178
test(libkernel): report native filesystem errors
2026-10-11 09:17:50 +02:00
Adrià 010fad317a
Merge pull request #3194 from XairRrR/feat/agc-8-8-swap-alt-blending
feat(agc-driver): blend into COLOR_8_8 SWAP_ALT targets with a separate alpha equation
2026-10-11 09:17:35 +02:00
Adrià a3aca02c5a
Merge pull request #3273 from MarcZX100/codex/fix-relinker-gnu-hash-3224
fix(relinker): read GNU hash symbols during code analysis
2026-10-11 09:17:31 +02:00
MarcZX100 c6c9e51439 docs(libkernel): document oversized select timeout 2026-10-11 09:17:07 +02:00
Adrià d508b44a20
Merge pull request #3259 from AchrafReyani/feat/libc-log1p-expm1
feat(libc): implement log1p, log1pf and expm1
2026-10-11 09:17:07 +02:00
MarcZX100 e864e687b3 fix(libkernel): saturate oversized select timeouts 2026-10-11 09:16:59 +02:00
Adrià a258e5e3e7
Merge pull request #3222 from fma-rc/fix/shader-implicit-lod-2d-on-1d
fix(shader): sample a 1D T# through a 2D implicit-LOD image_sample
2026-10-11 09:16:28 +02:00
Adrià a41bad9771
Merge pull request #3141 from MarcZX100/codex/carry-sce-dyn-3093
fix(relinker): read SCE dynamic tables from PT_SCE_DYNLIBDATA
2026-10-11 09:15:56 +02:00
raghav314 024cb1feda perf(agc): cache resources whose only completion work is the fault check
A draw or dispatch whose shaders have guarded descriptor slots (or a rect
list) but no BDA table gets a fault buffer, and with it NeedsCompletion(),
which kept its resources out of the resource cache, and NeverReusable
skipped the cache lookup for it. In PPSA36082 nearly every draw in the hub
is such a build, so the cache served none of them.

Such an object has no table to revalidate, no stores through BDA and no
copied writes, so it is now reusable. Each use of a reused object checks
the fault record when its batch completes (CheckFaults) instead of
running the once-only write-back; draw recipes over such a template
register the same check, and dispatch recipes still skip templates with
completion work. NeverReusable now refuses what noteReusable refuses: a
BDA table, or a fault buffer with APS5_LOOP_GUARD set (its fault resets
the buffer).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:15:53 +02:00
Adrià 1f2161bf5c
Merge pull request #2977 from MarcZX100/fix/shader-f64-denorm-preserve
fix(shader): preserve f64 denormals when supported by Vulkan
2026-10-11 09:15:32 +02:00
Adrià 7b98a306c0
Merge pull request #3160 from babyhuey/feat/libkernel-sys-fork
feat(libkernel_sys): export fork and implement setsid and umask
2026-10-11 09:14:48 +02:00
Adrià 5beb77f0f6
Merge pull request #3231 from Raghav314/perf/agc-pass-fault-only-draws
perf(agc): continue render passes across draws with only a fault buffer
2026-10-11 09:14:20 +02:00
Adrià 6e52fb8f8c
Merge pull request #3158 from XairRrR/perf/agc-host-import-spans
perf(agc-driver): import adjacent registered ranges as one host-import span
2026-10-11 09:14:15 +02:00
Adrià 19a3d0c8a9
Merge pull request #3213 from Raghav314/fix/libc-heap-without-gpu
fix(libc): register guest heap blocks without GPU access
2026-10-11 09:14:14 +02:00
Adrià 75c979ad9f
Merge pull request #3056 from TheAggie/feat/libkernel-get-app-info
feat(libkernel): implement sceKernelGetAppInfo
2026-10-11 09:12:54 +02:00
Adrià 833e5eb507
Merge pull request #3142 from MarcZX100/codex/carry-sce-scan-3093
fix(relinker): stop code scans at the PLT for PS4 executables
2026-10-11 09:12:30 +02:00
Adrià 1884f17d1e
Merge pull request #2140 from overlordxrz-source/fix/shader-volume-address-planar-texture
fix(shader): read 2D-array T#s through 3D image accesses
2026-10-11 09:12:23 +02:00
Adrià bbb9419642
Merge pull request #3129 from CnRJay/fix/windows-start-without-unused-library
fix(relinker): start on Windows without a missing library nothing imports from
2026-10-11 09:11:54 +02:00
Adrià bae9962954
Merge pull request #3108 from AchrafReyani/feat/opus-celt-dec-exports
fix(opus): export the libSceOpusCeltDec module
2026-10-11 09:07:53 +02:00
Achraf Reyani ffeb263654 feat(libc): implement fabs, trunc and fma
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:54:23 +09:00
MrMha 3b21873b35 test(agc): cover shutdown of unsatisfied memory waits
Extend the independently Windows-tested WAIT_REG_MEM candidate 056534a9 with a focused shutdown regression. Keep labels unsatisfied on graphics and two compute queues beyond the configured diagnostic, then require prompt shutdown without executing the commands or pending submissions behind those waits.

The production cancellation path already calls CheckFailure/checkStopping and catches ProcessShutdown in the worker; no runtime behavior is changed. This test does not explicitly open a Vulkan device.

Validation: Linux/GCC 13.3, C++20, -O2 -Wall -Wextra -Werror object compilation against the production headers; conventions and whitespace pass. CMake configuration, runtime linking and execution, and native Windows execution were not performed in this environment. Runtime verification remains pending. Depends on the persistent-wait candidate for #2832/#2985; maintainer policy approval is pending.

AI-assisted: yes.
2026-10-11 10:38:27 +04:00
Alex 54d4024c2b fix(shader): keep f32 subnormals in v_ldexp_f32 when denormals are kept
With the f32 denormal field of FLOAT_MODE set to keep, v_ldexp_f32
flushed subnormal inputs and results to zero. Keep subnormal inputs and
round a result that lands in the subnormal range in the f32 round mode
of FLOAT_MODE. An overflow follows the round mode as well, with or
without denormals kept: the largest finite value instead of infinity
when the mode rounds that sign toward zero. This matches RDNA2
(gfx1036) on 2163 rows in each round mode. Denormal modes 1 and 2 now
throw.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 02:36:48 -04:00
Alex b6cc4fe7f9 feat(videoout): implement sceVideoOutDeleteOutputModeEvent
Unsubscribe an event queue from the output mode events that
sceVideoOutAddOutputModeEvent registers, the same way the flip and
vblank events are removed. Deleting a registration that does not exist
succeeds, and a null queue or an invalid handle throws.

Co-Authored-By: Gemini 3.8 Flash <noreply@google.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 02:36:47 -04:00
Dean 1690db9a24
Merge pull request #3214 from fma-rc/fix/libs-bind-now
fix(libs): bind the system libraries eagerly on Linux
2026-10-11 19:35:33 +13:00
Dean 43c981462a
Merge pull request #3039 from CouchRiv/fix-shader-cvt-f32-int-directed-rounding
fix(shader): honor directed round32 in integer to f32 conversions
2026-10-11 19:35:24 +13:00
Dean 946df245ef
Merge pull request #3012 from CouchRiv/fix-shader-f16-directed-rounding
fix(shader): honor directed f16 rounding in f16 conversions and ldexp
2026-10-11 19:35:14 +13:00
Dean 52ce9b8af2
Merge pull request #3172 from LeandroLP23/feat/libc-memrchr
feat(libc): implement memrchr
2026-10-11 19:09:19 +13:00
Dean 4213dda236
Merge pull request #3278 from oneandonlydean/carry/alx-rne-tininess
perf(shader): check f32 product tininess in one multiply to nearest even
2026-10-11 19:09:09 +13:00
Dean ef3d996f39
Merge pull request #3277 from oneandonlydean/carry/alx-stencil-plane-view-reuse
fix(agc): treat other-shaped views of a depth surface's stencil plane as reused memory
2026-10-11 19:08:58 +13:00
Dean 0e90079fe5
Merge pull request #3192 from AchrafReyani/feat/libc-strsep
feat(libc): implement strsep
2026-10-11 19:05:36 +13:00
Dean 043aac6a4d
Merge pull request #3191 from AchrafReyani/feat/libc-rand-r
feat(libc): implement rand_r
2026-10-11 19:05:27 +13:00
Dean 7be5ce3de8
Merge pull request #3190 from AchrafReyani/feat/libc-hyperbolic
feat(libc): implement the hyperbolic functions
2026-10-11 19:05:17 +13:00
Dean b8075113b5
Merge pull request #3257 from AchrafReyani/fix/nid-names-leading-dash
fix(tools): accept NIDs starting with a dash in nid_names --nid
2026-10-11 19:05:08 +13:00
Dean de129cfd85
Merge pull request #3270 from MarcZX100/codex/fix-fp16-overflow-skip-3230
test(agc): skip fp16 overflow without shaderFloat64
2026-10-11 19:04:58 +13:00
SynnZer0 8ad1bcb589 fix(libkernel): ignore the input st_size of sceKernelGetModuleInfoFromAddr
The bundled libc.prx of PPSA21703 calls sceKernelGetModuleInfoFromAddr
with a 0x1A8-byte stack buffer and never sets st_size, so the field holds
whatever was on the stack (983040 in one run) and the call threw. The
console cannot require the field on input. The full size is still
written back. The flags check is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:02:38 -04:00
Adrià Franch fdc0b5268b docs(technical-debt): record the NGG vertex mesh routing assumptions 2026-10-11 07:56:42 +02:00
Scott Schuster 0e3449129e fix(agc): accept any ES VGPR count for NGG vertex programs on the mesh path
vkQuake's NGG culling vertex shaders load only the vertex ID
(SPI_SHADER_PGM_RSRC2_GS ES_VGPR_COMP_CNT 0), and DecodeShaderStages still
required 3 for a program routed to the mesh path. The merged ES inputs keep
their positions whatever the count, and the mesh entry loads all of them,
so the count is now checked only for real geometry programs, as the GS
VGPR count already was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:56:37 +02:00
Scott Schuster 0a1b31f5c4 test(agc): cover NGG vertex programs routed to the mesh path
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:56:37 +02:00
Scott Schuster a48b39e933 feat(agc): run unregistered NGG vertex programs that need a workgroup on the mesh path
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:56:37 +02:00
Dean 4be74d4f06
Merge pull request #3269 from MarcZX100/codex/fix-prepared-shaders-depth-range-3207
test(agc-driver): set D3D clip range for shared-code draw
2026-10-11 18:55:13 +13:00
Dean 7edd75e106
Merge pull request #3169 from AchrafReyani/fix/test-windows-symlink-privilege
test(libkernel): skip the Windows lstat link checks without the symlink privilege
2026-10-11 18:55:03 +13:00
Dean eee0eeaa49
Merge pull request #3091 from MarcZX100/codex/fix-videoout-output-mode-fixture
fix(test): restore the VideoOut output mode fixture
2026-10-11 18:54:54 +13:00
Dean b7222870c9
Merge pull request #3200 from hugodearaujo/feat/rudp-status-console
fix(libSceRudp): match the console's init and status checks
2026-10-11 18:54:38 +13:00
Dean 6db55f7718
Merge pull request #3110 from Recapi/feat/pad-vr-controller-read-state
feat(libScePad): export scePadVrControllerReadState
2026-10-11 18:54:29 +13:00
Dean af08c417eb
Merge pull request #2887 from babyhuey/feat/libsceaudioout-sys-hdmi-monitor-info
feat(libSceAudioOut): export the sceAudioOutSys HDMI output functions
2026-10-11 18:54:19 +13:00
MrMha 056534a969 test(agc): finish persistent label waits with real producers
Apply the three-case test correction offered by Scramblrrrr in 36b26122a5458028f76fe7c7710333fcfca80f6d on issue #2832. Preserve all current-main test additions outside those three functions. Credit the supplied implementation to its contributor.

Independent Windows Vulkan results and the timeout-return negative control are reported in issue #2832. Local validation: exact three-function source match, preservation of unrelated Submit.cpp content, conventions and whitespace. Native Windows/GPU execution was not performed here. Shutdown cancellation and persistent-wait policy remain unresolved.

AI-assisted: yes.

Co-authored-by: Scramblrrrr <70121301+Scramblrrrr@users.noreply.github.com>
2026-10-11 09:54:17 +04:00
MrMha 49a50abd80 chore(agc): synchronize wait fix with current main
Retain the original WAIT_REG_MEM fix from #2985 and resolve its test-registration conflict with main d7cfa728. Preserve both upstream test blocks and the original commit ancestry.

Local conventions and whitespace checks pass. Windows/GPU results cited in issue #2832 belong to their reporting contributors. No local GPU execution.
2026-10-11 09:53:09 +04:00
Dean 304c745c45
Merge pull request #2894 from MarcZX100/fix/test-net-ipv6-unavailable-loopback
test(net): skip IPv6 checks when host loopback is unavailable
2026-10-11 18:50:57 +13:00
Adrià Franch 41b2841b0a docs: format sceAppContentGetAddcontDownloadProgress technical debt line
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 07:48:17 +02:00
Leonardo 228c8a0d6e docs: document sceAppContentGetAddcontDownloadProgress in technical debt 2026-10-11 07:48:11 +02:00
Leonardo 6aa9128eb3 feat(libSceAppContent): implement sceAppContentGetAddcontDownloadProgress 2026-10-11 07:48:11 +02:00
Dean d7cfa72813
Merge pull request #3150 from MarcZX100/codex/marc-socket-vector-io
fix(libkernel): route vector I/O on guest sockets
2026-10-11 18:47:36 +13:00
Dean b64cc2ce44
Merge pull request #3053 from MarcZX100/codex/libkernel-rmdir-read-only-3049
fix(libkernel): remove read-only directories with rmdir on Windows
2026-10-11 18:44:11 +13:00
Dean 0cf94023b6
Merge pull request #3047 from babyhuey/feat/libkernel-pthread-kill
feat(libkernel): implement pthread_kill
2026-10-11 18:44:02 +13:00
Dean 9480e0c253
Merge pull request #3173 from LeandroLP23/fix/agc-library-module-lifetime
fix(agc): keep a shader library part's modules until the part is destroyed
2026-10-11 18:43:54 +13:00
Adrià Franch 4474548223 docs(libSceJobManager): move the TechnicalDebt line off the end of the section 2026-10-11 07:40:46 +02:00
fma-rc 8897c5ceac fix(libSceJobManager): count a wait before serialising it and close under the lock 2026-10-11 07:40:37 +02:00
fma-rc e2a7aac32d feat(libSceJobManager): implement CPU job sequences 2026-10-11 07:40:37 +02:00
Dean 90f26c996c
Merge pull request #3031 from TheAggie/feat/libkernel-pthread-set-name-np
feat(libkernel): implement pthread_set_name_np
2026-10-11 18:40:30 +13:00
Dean 4f6024863e
Merge pull request #2918 from XairRrR/feat/videoout-vrr-peg
feat(libSceVideoOut): accept VRR peg and unpeg on a fixed-rate output
2026-10-11 18:37:08 +13:00
tototomate123 63d29116b4 fix(http): retain request status callbacks with the guest ABI 2026-10-11 07:36:46 +02:00
Dean f90ccd797a
Merge pull request #1732 from TheAggie/feat/agc-raw-graphics-programs
feat(agc): accept graphics programs without an AGC shader header
2026-10-11 18:33:47 +13:00
Adrià Franch b299350a7a docs(debt): record the unverified ForEach resolve count 2026-10-11 07:27:53 +02:00
tototomate123 65c8ef656f fix(apr): compact gather records to avoid command buffer exhaustion 2026-10-11 07:27:52 +02:00
tototomate123 f514df98de fix(apr): match the guest command buffer object layout 2026-10-11 07:27:52 +02:00
tototomate123 68900523c4 fix(apr): report guest errors and clear failed file resolutions 2026-10-11 07:27:52 +02:00
Dean f5c0fe00f7
Merge pull request #1463 from drk1rd/fix/agc-amd-sdwa-f16
fix(shader): convert f16 bits to f32 without UnpackHalf2x16
2026-10-11 18:27:10 +13:00
Dean 1ae5b2fe5a
Merge pull request #3258 from oneandonlydean/carry/2480-vertex-fetch-aliasing
fix(shader): preserve aliased embedded fetch attributes
2026-10-11 18:23:47 +13:00
krishnaraya d041c183df test(agc): skip flat aperture 64-bit atomic rows without shaderBufferInt64Atomics
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 01:21:40 -04:00
Dean be3014ae58
Merge pull request #3137 from johnmaia/perf/agc-write-back-sse2
perf(agc): store write-back changes sixteen bytes at a time
2026-10-11 18:20:23 +13:00
Dean 33c0cffb7e
Merge pull request #3134 from SleglJan/feat/agc-display-rgba16-float
feat(agc): present 16-bit float display buffers
2026-10-11 18:20:13 +13:00
MarcZX100 bde216731e fix(libc): preserve dirname input paths 2026-10-11 05:12:21 +00:00
MarcZX100 fcc3145abf fix(libc): apply range handling to llroundf
The original fix predates llroundf, which was added in #2933. Use the same guest range and exception behavior for the fourth wrapper and include it in the edge-case checks.
2026-10-11 05:11:23 +00:00
Hussein Kadhim 03dde075c9 fix(libc): raise FE_INVALID explicitly and leave errno untouched in lround family
(cherry picked from commit a56de63b8ae0e4bef888ec24ed7f737ab9cab9f7)
2026-10-11 05:11:23 +00:00
Hussein Kadhim 6c87593a16 fix(libc): return LONG_MIN from lround, lroundf and llround out of range
FreeBSD amd64 converts the rounded value with a plain cast, so NaN, infinities and values outside the 64-bit range give 0x8000000000000000 with FE_INVALID raised. The Windows host llround returns 0 for them.

(cherry picked from commit 0ee2741534bdfcc9d818b1d93f2eb793a68f111e)
2026-10-11 05:11:23 +00:00
MarcZX100 7d7b405b3c test(libc): cover dirname separator and boundary cases 2026-10-11 05:10:13 +00:00
MarcZX100 865e530505 feat(libc): implement dirname 2026-10-11 05:10:13 +00:00
Fishybeing 007cc62555 fix(libc): follow FreeBSD's memset_s errors
FreeBSD's memset_s returns EINVAL for every constraint violation and writes nothing when smax or n exceeds RSIZE_MAX. The guest returned ERANGE when n exceeded smax and wrote up to min(n, smax) bytes even when smax or n exceeded RSIZE_MAX.

(cherry picked from commit bf08837cf929e40f1b646df82e140a33076d5587)
2026-10-11 05:05:02 +00:00
Dean 7f1dc9658a
Merge pull request #3226 from oneandonlydean/up4/fix-unit-shadow
fix(agc): compare host imports when device writes reach the write watch
2026-10-11 18:03:00 +13:00
AlxcBTW fda4aa90c9 fix(shader): let image writes, explicit-LOD gathers and size queries pass the masked-lane walk
Following the ImageRead case, every image operation was checked against
the two lists the masked-lane walk uses: accesses guarded by a trailing exec
operand, and lane-local values.

- ImageWrite carries its exec last like StoreBuffer, and EmitWriteOp stores
  only inside an if on it (bindless tables and FMASK refuse the store). It
  joins the exec-guarded list.
- A gather with an LOD of its own (gather4_l, gather4_lz) or outside a pixel
  shader reads only its lane's address, like the explicit-LOD samples the
  walk already follows. A pixel gather without one still keeps the select,
  since on the GPU it takes its LOD from the quad.
- ImageQueryDimensions returns the size of its lane's level of the image and
  is lane-local.

Left out on purpose:
- ImageQueryLod and implicit-LOD samples read their quad.
- ImageBvhIntersectRay has a trailing exec operand, but its emitter ignores
  it and records faults in every lane.
- Image, buffer, shared and address atomics are guarded by their exec in the
  emitter too, but the test from 60c65521 pins them as keeping the select,
  and no refused shader has needed them so far.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:55:54 +13:00
xXPBSXx 83f8c193c9 fix(shader): treat an image read as a use that only reads where its exec is active
An ImageRead carries a trailing exec argument like the buffer loads, but it
was in neither the read-only-where-active list nor the lane-local list, so a
masked select feeding its address was kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 17:55:54 +13:00
AlxcBTW 98f99d3883 fix(shader): prove masked lanes unread across loops
Kena: Bridge of Spirits (PPSA01802) refuses ten pixel shaders with

  packed pixel ancillary input has an unsupported live use (used by SelectU32 ? ?)

at any visit limit. All ten have 30 to 33 phis on loop back edges (reported
on Linux with an RX 9070 XT).

Two rules stopped the proof at a loop, and the first one fires before the
second is ever asked:
- The walk from the select gave up at the first use inside a loop. A value
  derived from the select reaches a loop phi as soon as its register is
  written inside the loop, because the masked write becomes
  Select(loopExec, new, phi). A loop that leaves exec alone needs nothing
  more than this.
- An exec that a loop narrows and carries around its back edge is a phi
  inside the loop, and such phis counted as not implying the write's exec.

The walk now follows uses into loops. A phi inside a loop implies the
write's exec when all of its incoming values do, where the phi itself counts
as implying it while its back-edge values are checked. This is sound because
each rule of the proof takes a lane bit of one value from a value computed
earlier: a phi's value on each iteration is the incoming value computed
before the edge was taken, a set lane of an And is set in both operands, a
set lane of a ballot is a lane whose predicate held. If any value in the
proof had a lane set where the write's exec is clear, the earliest such
value would take that lane from an earlier value of the proof that is set
there too, which contradicts it being the earliest. Two conditions keep this
true:
- The write's exec must be computed once, outside every loop. Otherwise a
  phi can carry a ballot of it from an earlier iteration, which is not the
  value the select used. Masks computed inside a loop keep the old rules.
- A result may only be kept if the assumptions it used held. When a value
  that was assumed turns out not to be implied, every result recorded since
  it was assumed is dropped. Results that say "not implied" are kept; they
  only make the proof refuse more.

A lane that is turned back on inside the loop makes the back-edge exec wider
than the write's exec, so the phi is not implied and a read under it keeps
the select. A lane that is turned back on but never reads the derived value
does not.

New tests cover a loop that carries the write with exec saved, narrowed and
restored (read inside and after the loop), a loop that leaves exec alone,
and the helper-only ancillary select feeding such loops. The refusing tests
each fail when the matching check is removed: a revived lane that reads the
write inside the loop (ignoring back-edge values), a result proven under an
assumption that later fails (keeping it), and a write mask computed inside
an earlier loop (allowing such masks). Two existing tests expected a loop to
keep the select although every read is under the write's own exec; they now
expect it to go, next to new counterparts with a wider exec.

On the Taxi Chaos 2 requests, compute shaders with a loop inside a branch now
lose the branch's masked writes: 0x194000b400 removes 207 selects instead of
36, 0x19002bd200 111 instead of 28, and seven more gain 5 to 43. In
0x16400cf700 the 26 new removals are writes under the branch condition
tid < count; the loop's exec starts as a ballot of that condition, only loses
lanes at the latch, and every store and atomic inside the loop runs under it.
No proof on these requests had to drop a result.

Walks now go on into loops, so the pass takes longer on loop shaders, but it
stays below main. Time in MaskedSelectEliminator per prepare (median of 3,
the pass runs twice per prepare), 54 Taxi Chaos 2 requests, one run:

  shader          previous commit   this commit   main 5edae353
  0x1ac0413000         334 ms           349 ms         424 ms
  0x19002bd200          38 ms           103 ms         112 ms
  0x19c016aa00           9 ms            74 ms          16 ms
  0x194000b400          13 ms            31 ms          32 ms
  all 54               547 ms           805 ms         977 ms

0x19c016aa00 removes nothing more; its walks only end later inside its
loops. The 144 requests of the NVIDIA dump go from 1283 to 1589 ms and gain
removals in the copies of the same shaders. 197 of the 198 requests prepare,
as before.

Related: #2548

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:55:54 +13:00
AlxcBTW cd4eaacf7c perf(shader): scale the masked-lane walk limit with the program
LEGO Horizon Adventures (PPSA14632) still refuses a pixel shader with

  packed pixel ancillary input has an unsupported live use (used by SelectU32 ? ?)

although it has the form the previous commit handles: the only whole-word
reader is SelectU32(IEqual32(HelperInvocation, 0), BitFieldUExtract(x, 0, 11),
ancillary), the exec words are Ballot(not helper) & Ballot(true), and there
are no image ops, stores or loop phis. About 10,250 IR values derive from the
word, so the walk from that select stops at its fixed limit of 4096 visited
values and the select is kept. With the limit raised to 8192 the shader
prepares (reported on Linux with an RX 9070 XT).

A walk may now take max(4096, 2 * instructions) steps. A step is a value
visited for the first time or an implication evaluated for the first time.
The walk only visits values derived from the select, at most one per
instruction, so a walk is only cut short when the implications it evaluates
cost as much as the program itself. On the 198 Taxi Chaos 2 requests no walk
needs more than 0.79 * instructions steps. One walk stays linear in the
program, O(instructions + operands): each value is expanded once, and with
the per-walk memo each implication is evaluated once.

The walk is also cheaper, so that the larger limit costs nothing:
- visited values are marked in a table indexed by value id instead of a hash
  set, and the table, the work list and the memo are reused across walks;
- blocks outside loops are looked up in a table indexed by block id instead
  of a hash set. This lookup ran once per use and was most of the pass's time.

Time in MaskedSelectEliminator per prepare (median of 3, the pass runs twice
per prepare), 54 Taxi Chaos 2 requests:

  shader          before 40a8a5a7   this commit   main 5edae353
  0x1ac0413000         689 ms           285 ms         401 ms
  0x19002bd200         102 ms            34 ms         100 ms
  0x18c07bf000         191 ms            52 ms     (refused)
  all 54              1294 ms           484 ms         919 ms

0x1ac0413000 and its three copies in the NVIDIA dump now remove 659 selects
instead of 625: their walks no longer stop at 4096. No other request changes
what it removes. 197 of the 198 requests prepare before and after; the other
one fails the same way in both (v_readlane_b32 of lane 63 on a 32-lane host
subgroup).

Related: #2548

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:55:54 +13:00
AlxcBTW c2a48416b1 fix(shader): follow exec phis and long kill chains when proving masked lanes unread
Taxi Chaos 2 (PPSA30279) pixel shader 0x18c07bf000 is refused when it is
registered, and the title stops:

  packed pixel ancillary input has an unsupported live use (used by SelectU32 ? ?)

The shader reads the ancillary VGPR (v2) once, with v_bfe_u32 v3, v2, 16, 11,
which #1904 lowers to Layer. The next write to v2, v_rcp_f32 v2, s33, runs
before any kill under the initial exec and becomes
SelectU32(IEqual32(HelperInvocation, 0), rcp, ancillary). The raw word
therefore survives only in helper lanes. The shader has no s_wqm, no DPP,
readlane or swizzle, no stores, and only *_lz samples and gathers. Every
helper-lane value that comes from v2 is dropped by a later exec select, a
compare that is ANDed with exec before its ballot, or an export whose exec
excludes helper lanes.

MaskedSelectEliminator exists to remove selects like this one, but it could
not prove the case. The kill paths save and restore exec, so the later execs
are phis at block merges, and the AND chains the kills build go deeper than
its eight-level limit.

When it checks whether a later exec implies the write's exec, it now:
- accepts a phi when the phi and each incoming value lie outside loops and
  every incoming value implies that exec;
- pairs low and high exec words merged by phis in one block, predecessor by
  predecessor;
- memoises results for each select and follows up to 64 levels. A cycle
  counts as not implied.

Once the select is gone, nothing reads the ancillary word, so no bit of it
is produced. A select whose false lanes can still be observed is kept and
the shader is still refused. That covers a data test that leaves the word in
non-helper lanes that later export, an export under the full wave, and an
unmasked ballot.

Related: #2548

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:55:54 +13:00
MarcZX100 c53a31bb1d test(libkernel): report native filesystem errors 2026-10-11 04:53:40 +00:00
ArjenS-LA 4bc36b19b8 fix(relinker): read GNU hash symbols during code analysis
When the dynamic symbol count is absent from the SCE or SysV hash metadata, derive it from the GNU hash buckets and chain. Keep all table reads within mapped file-backed ranges.

Carried from issue #3224, commit 1a10126089882a2306318f18d19d05b04a764d6c; original author preserved.
2026-10-11 04:48:55 +00:00
Abdulrahman Elkordy 4d82201f72 test(agc): skip fp16 overflow without shaderFloat64
The fp16 overflow shader translates to 64-bit float instructions, so a device without shaderFloat64 cannot run this test. Skip before recompiling on unsupported devices.

Carried from issue #3230, commit 922d4015e05c34f616912e1913854007a5d689bf; original author preserved.
2026-10-11 04:44:29 +00:00
Achraf Reyani dd9c78aa1b fix(tools): stop collecting NIDs at abbreviated options and --nid=
Resolve each argument after --nid against the parser's option strings the
way argparse does, so --nid=B, abbreviations such as --j and --d=, and the
-- marker end the NID list instead of being taken as NIDs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:24:35 +09:00
Abdulrahman Elkordy d8172fb7dd test(agc-driver): give the shared-code header draw a [0, 1] depth range
SharedCodeHeaders draws on the initial context, whose PA_CL_CLIP_CNTL
selects the [-1, 1] clip space with viewport Z scale 1 and offset 0, so
the draw asks for a viewport depth range of [-1, 1]. Devices without
VK_EXT_depth_range_unrestricted, such as Intel GPUs on Windows, reject
that and the test fails before it reaches registration. Set
DX_CLIP_SPACE_DEF as the other draw tests do.

(cherry picked from commit 3c3bcf8f80cceaba4aa1f8742c32251fcc143e6b)
2026-10-11 04:23:22 +00:00
GalaxyGamingFR 3dbcc5f1c7 fix(tools): keep apostrophes in comments from opening character literals
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 21:21:07 -07:00
fma-rc 25afd95d35
fix(font): keep the step fields the library leaves alone and test multi-level closing 2026-10-11 05:55:36 +02:00
fma-rc eecba6888d
feat(font): order writing line runs by embedding level and report their spacing 2026-10-11 05:48:07 +02:00
MarcZX100 3d79d42663 test(net): include Windows IPv6 declarations
(cherry picked from commit 811d8c6b155fbfdae5e5277f90b435e68d42ffdc)
2026-10-11 03:47:17 +00:00
MarcZX100 2c012b4fe5 test(net): skip unavailable IPv6 loopback checks
(cherry picked from commit 9f2a0062d580b399424cb417e7f2a17cd093785b)
2026-10-11 03:47:17 +00:00
Achraf Reyani 1f94d93d06 feat(libc): implement log1p, log1pf and expm1
Export them forwarding to the C++ standard library, like log and exp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:42:00 +09:00
Adrià Franch aa91d9144c test(agc): pass the GPU flag to GuestAllocations Add in the one-slice alias test 2026-10-11 05:41:07 +02:00
Nahuel Genchi 247e3f5eb2 perf(agc): take a 2D storage image's results for a one-slice array on the device
A 2D surface and a one-slice 2D array over the same memory are separate
storage images, since the storage key holds the dimension. pendingAlias
only took a pending image of the same dimension, so a refresh of one
view wrote the other view's results back and uploaded them again.
Sonic Origins Plus (PPSA05324) switches between the two views of the
same surfaces about 50 times a frame in its opening animation.

pendingAlias now counts a 2D surface and a one-slice 2D array as the
same dimension. The rest of the shape test (size, array range, mips,
tiling, element size, image layers and depth, tracked units) and the
conditions of the device copy (uncompressed keys, a host import, the
surface's write stamps) are unchanged.

agc_driver_storage_one_slice_alias stores through the 2D view twice and
loads through the array view after each store. It checks the texels
read through the array, that the 2D image is still pending after the
array image's refresh (where the imported block is write-watched), and
the guest memory after the final flush. Without the change the pending
check fails on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:41:03 +02:00
Achraf Reyani 7f9ca519b4 fix(tools): accept NIDs starting with a dash in nid_names --nid
NIDs use the base64 alphabet with '-', so some start with a dash, such as
-nvxBWa0iDs (gethostname). argparse read such a value after --nid as an
option and nid_names.py stopped with "unrecognized arguments". Every
value after --nid up to the next option of the tool is now passed as
--nid=<value>, and --nid collects them with append.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:40:04 +09:00
MarcZX100 16adcd4871 fix(relinker): validate SCE dynamic data segment 2026-10-11 03:30:09 +00:00
Get-fix ef727569cc fix(relinker): read SCE dynamic tables from PT_SCE_DYNLIBDATA
DT_SCE_STRTAB, DT_SCE_SYMTAB, DT_SCE_RELA and DT_SCE_JMPREL are offsets
into the PT_SCE_DYNLIBDATA segment, as the code analysis and the guest
image reader already read them, but the pipeline read them as file
offsets. That only works when the segment starts at file offset 0, as in
the test fixtures. A PS4 executable (CUSA00900) keeps the segment at
0x53e9b40, so the relinker read its relocations from the code and failed
with "Dynamic string offset is outside DT_STRSZ". Without the segment the
values are still read as file offsets.

(cherry picked from commit 5dbf89a57e096f2891ae786f44c3f57935af2285)
2026-10-11 03:25:49 +00:00
MarcZX100 5e00b269ca test(shader): run f64 denorm cases without preserve mode 2026-10-11 03:09:34 +00:00
MarcZX100 ebaa687d36 fix(shader): respect float control independence 2026-10-11 03:09:34 +00:00
ThatsLeo 24c4dbae1e fix(shader): keep f64 denormals where the device can preserve them
Shaders with f64 instructions now declare DenormPreserve for 64-bit floats
when the device reports shaderDenormPreserveFloat64. Without it Mesa ANV
flushed the subnormal result of v_fma_f64 to zero.

(cherry picked from commit 7df6c709de994cea0019707d45b6e7b96698fad1)
2026-10-11 03:09:34 +00:00
Adrià Franch a585ec1d62 test(agc): resolve the register COPY_DATA from an aligned address
0xa00a is not 4-byte aligned, so ResolveStore rejected it before the register guard.
2026-10-11 05:05:58 +02:00
Scott Schuster fdf683ac1b fix(agc): run a partial last thread group through the shader and validate every axis
The buffer fill and copy fast paths returned before the partial last group
was applied, so a PARTIAL_TG_EN dispatch of the fill kernel filled whole
groups, and a zero last group did not throw. The partial sizes are now
decoded before the fast paths, which are skipped when the last group is
partial; the dispatch then runs the shader with the partial thread counts.

PartialGroupThreads validates all three axes before an empty dispatch
returns, and throws when (groups - 1) * full + last does not fit in 32 bits
instead of wrapping. Validate rejects PARTIAL_TG_EN combined with
USE_THREAD_DIMENSIONS (initiator 0x63).

agc_driver_pattern_buffer_fill now runs the fill kernel with a 16-of-64 last
group through the driver and checks that 80 dwords are written.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 44abcc43b1 feat(agc): accept 4-byte-aligned indirect argument bases
RADV sets the draw and dispatch indirect base with SET_BASE to the
argument buffer address plus the command's offset, which Vulkan requires
only to be a multiple of 4; vkQuake's base ends in 0x14. The validator
required 8-byte alignment. The records are read as 32-bit words, so a
4-byte-aligned base is now accepted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 40f243facc feat(agc): read indirect draw register location 0 as no register
RADV emits 0 as the start-instance location of DRAW_INDIRECT and
DRAW_INDEX_INDIRECT when the vertex shader does not read the base instance,
and as the draw-index location of the multi forms when draw IDs are off.
The validator accepted only 0x280 as "no register". Location 0 is now
accepted and decoded as 0x280; vkQuake's draws use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 01909c914e feat(agc): accept dispatches that launch waves in order
RADV clears ORDER_MODE in the dispatch initiator for a dispatch that
needs its waves launched in order, and the validator required it set.
In-order launch is the stricter guarantee and the driver does not reorder
waves either way, so a direct or indirect dispatch now needs only
COMPUTE_SHADER_EN; vkQuake's map load issues one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 4390d4b7a5 feat(agc): accept COPY_DATA to memory through DST_SEL 5
RADV writes every COPY_DATA memory destination with DST_SEL 5
(COPY_DATA_DST_MEM in Mesa's sid.h), the current form of the deprecated
GRBM-synchronized DST_SEL 1 that was already accepted. vkQuake's timestamp
writes use it. It is now validated, resolved and executed as memory like 1
and 2; GDS and performance-counter destinations are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 2dad44f8df feat(agc): load context registers from memory with COPY_DATA
Where the GPU has no LOAD_CONTEXT_REG_INDEX, RADV loads an image's clear
values into DB_STENCIL_CLEAR/DB_DEPTH_CLEAR and CB_COLORn_CLEAR_WORD0/1
with COPY_DATA from memory to a register (DST_SEL 0), one or two dwords.
The validator rejected every register destination.

A COPY_DATA from memory to one or two context registers is now accepted.
It is not a memory store, so the packet drains like other COPY_DATA the
driver cannot record on the GPU, and executing it reads the source then and
writes the registers. Register, GDS, immediate and clock sources, and
destinations outside the context registers, are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Scott Schuster 13c03910a4 feat(agc): run RADV's dispatches with a partial last thread group
RADV sets PARTIAL_TG_EN in the dispatch initiator for an unaligned direct
dispatch, with each axis's last-group size in the upper half of
COMPUTE_NUM_THREAD_X/Y/Z, and TUNNEL_ENABLE on every GFX10 dispatch. The
validator rejected PARTIAL_TG_EN, and DecodeComputeStageInfo read the
whole register, so a partial size would have widened the workgroup.

A direct dispatch with PARTIAL_TG_EN now runs (groups - 1) * full + last
threads on each axis through the dispatch-size limit USE_THREAD_DIMENSIONS
already uses, or plain groups when every last group is complete; a zero
or oversized last group throws. The workgroup size is NUM_THREAD_FULL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 05:05:55 +02:00
Cesar Rodriguez 8d96b44917 fix(libSceAgc): accept a null base in sceAgcDcbSetBaseIndirectArgs
The builder threw on a null indirect base, while the PM4 executor accepts
SET_BASE with address 0 (it only requires the alignment and address bits) and
an indirect draw that later reads the base is checked there. Titles clear the
base with 0, as with sceAgcDcbSetIndexBuffer, which already accepts 0 to
unbind. A non-null base is still checked for 8-byte alignment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 20:05:51 -07:00
Chad 86d6624323 fix(agc): copy a sparse descriptor heap only up to its last backed byte
Co-authored-by: Scramblrrrr <Scramblrrrr@users.noreply.github.com>
2026-10-11 04:56:40 +02:00
Adrià 961b25fe24
Merge pull request #3233 from adriadam10/feat/libc-sqrt
feat(libc): implement sqrt and sqrtf
2026-10-11 04:53:47 +02:00
Adrià Franch bf779b2d71 docs(technical-debt): move the depth copy line off the end of the file 2026-10-11 04:52:43 +02:00
Joey Fisher b384183505 test(agc): pin the depth copy path, its refresh on reuse, R16 and several mips and layers; drop APS5_NO_DEPTH_COPY 2026-10-11 04:52:36 +02:00
Joey Fisher d024709cff perf(agc): sample comparison-read R32F/R16 surfaces from a GPU depth copy of their storage image 2026-10-11 04:52:36 +02:00
Adrià 6c9cb3a5db
Merge pull request #3225 from adriadam10/feat/libc-malloc-usable-size
feat(libc): implement malloc_usable_size
2026-10-11 04:49:41 +02:00
Adrià Franch 660abec2d3 feat(libc): implement sqrt and sqrtf
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 04:44:39 +02:00
Adrià Franch 859f2f3b92 feat(libc): implement malloc_usable_size
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 04:41:39 +02:00
raghav314 70a6dde689 perf(agc): continue render passes across draws with only a fault buffer
A recorded draw counted as reading and writing any guest memory when its
resources needed completion work, which a fault buffer alone (guarded
descriptor slots, rect lists) also needs. Such a draw reaches no guest
memory through it: the buffer is the draw's own, written only on a fault.
Its pass hazards now come from its known ranges and images like any other
draw; address-based draws, draws through the BDA table and draws with
copied writes still count as touching any guest memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:53:23 +05:30
Adrià aac0f1b810
Merge pull request #3229 from adriadam10/carry/libc-random-state
feat(libc): implement random, srandom, initstate and setstate
2026-10-11 04:15:28 +02:00
Adrià Franch b1267b3388 docs(technical-debt): list the random family under unknown function info
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 04:07:59 +02:00
David 1671179c4f feat(libc): implement random, srandom, initstate and setstate
Port FreeBSD 11 lib/libc/stdlib/random.c (freebsd-src 4ab2e064): the
additive feedback generator with the default 128-byte TYPE_3 table,
good_rand seeding, state sizes rounded down to 8, 32, 64, 128 or 256
bytes, setstate returning the previous state, and initstate returning
null below 8 bytes without setting errno. Calls are serialised by one
lock; a null state throws.

The import audit of the homebrew catalog on main 262c0316 lists them as
absent libSceLibcInternal imports:
- random: PPSA74126 Stremio Plus, PPSA85300 VLC, PPSA99169 RetroArch,
  PPSA99177 PS5VR, PPSA99420 PS5MC, PPSA99505 Jelly5, PPSA99515 Emby5,
  PPSA99810 PSBox Cloud Gaming
- srandom: PPSA85300, PPSA99169, PPSA99420, PPSA99810
- initstate, setstate: PPSA99177, PPSA99420, PPSA99505, PPSA99515

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 04:07:38 +02:00
Adrià 84cc975e7d
Merge pull request #3221 from adriadam10/feat/libc-acosl-frexpl
feat(libc): implement acosl and frexpl
2026-10-11 04:06:58 +02:00
Adrià Franch 250b617f14 docs: record the two-pass blend into 8_8 SWAP_ALT targets 2026-10-11 04:00:52 +02:00
XairRrR ba0b042925 feat(agc-driver): blend into COLOR_8_8 SWAP_ALT targets with a separate alpha equation
An 8_8 target with SWAP_ALT keeps the x export in its first channel and
the alpha export in its second, and the color block blends that second
channel with the alpha equation. Blending into such a target threw.

With one equation for color and alpha the draw blends as before. With a
separate alpha equation the pipeline draws twice: the first pass writes
the first channel with the color equation, the second writes the second
channel with the alpha factors and operation moved into its color
equation. The split is refused, by throwing, for draws that write depth
or stencil, use per-face depth bias, or whose pixel shader writes memory,
since those would repeat; factors of the destination alpha throw since
the target keeps it in its second channel. Pipeline libraries are not
used for split pipelines.
2026-10-11 04:00:44 +02:00
Adrià Franch 05b3f6e40d fix(agc): update the DescriptorBinding size assert for samplerIntegerBorder
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 03:59:03 +02:00
Adrià Franch 3cd36b0135 feat(libc): implement acosl and frexpl
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 03:58:47 +02:00
fma-rc 8132ac7a21
docs(debt): state the measured steps and the non-pixel LOD of a 2D implicit-LOD sample on a 1D T# 2026-10-11 03:57:24 +02:00
krishnaraya 1ce9790481 fix(agc): pick float or integer sampler border colours from the paired images
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 21:57:09 -04:00
Adrià 6040a9626e
Merge pull request #3217 from adriadam10/test/agc-flat-apertures-parts
test(agc): split agc_driver_flat_apertures into six parts
2026-10-11 03:55:38 +02:00
fma-rc eb2c43a2eb
fix(shader): sample a 1D T# through a 2D implicit-LOD image_sample
A plain image_sample that says DIM 2D on a 1D T# takes its texel and its LOD
from the first coordinate alone, measured on RDNA2 (gfx1036) with the
hardware oracle. Astro's Playroom draws with such a pair.
2026-10-11 03:54:50 +02:00
Gustavo Ariel Gamarra Rojas 50e84c7cf7 test(agc): pin alpha-to-coverage coverage measured on RDNA2
The expected rows were measured with Vulkan alpha-to-coverage on a Radeon 660M (gfx1035) under RADV_DEBUG=noatocdithering, which programs DB_ALPHA_TO_MASK 0xaa01: an alpha of at least one half, 2 and +inf keep the pixel; below one half, -0, negatives, -inf and NaN drop it.
2026-10-10 22:50:46 -03:00
Gustavo Ariel Gamarra Rojas 869d73e4d8 test(libSceSysmodule): compare sceSysmoduleGetModuleInfoForUnwind with /proc/self/maps
Covers code, stack and an anonymous page, and an unmapped address. On Linux the test runs again with APS5_NO_PROCMAP_QUERY so the line scan stays covered.
2026-10-10 22:50:46 -03:00
Gustavo Ariel Gamarra Rojas 7d92bf70f9 feat(agc): decode undithered alpha-to-coverage
DB_ALPHA_TO_MASK 0xaa01, the enable bit with the four offsets at 2 and no OFFSET_ROUND, reaches the pixel stage, which keeps a pixel when its MRT0 alpha is at least one half. Dithered or rounded settings, and an MRT0 that is missing, swizzled, packed or exported without a floating-point alpha, still throw. God of War Sons of Sparta (PPSA28997) stopped on it a few minutes into play.
2026-10-10 22:50:46 -03:00
Gustavo Ariel Gamarra Rojas ad4add2b1a perf(libSceSysmodule): look up the mapping with PROCMAP_QUERY in sceSysmoduleGetModuleInfoForUnwind
It carried its own copy of the /proc/self/maps line scan and is called on the same Unity stack walks as sceKernelGetModuleInfoForUnwind. It now uses the shared HostMapping lookup.
2026-10-10 22:50:46 -03:00
Gustavo Ariel Gamarra Rojas d152ff833c feat(shader): turn the MRT0 alpha into a sample mask for alpha-to-coverage
A pixel shader whose stage info asks for alpha-to-coverage declares SampleMask, starts with every sample covered and, at its MRT0 export, clears the mask when the alpha is below one half or NaN, running with late fragment tests. The shader keeps running, as a zero coverage mask does on the GPU. The flag is part of the static shader identity and of the request serialization, now version 16.
2026-10-10 22:50:46 -03:00
Gustavo Ariel Gamarra Rojas 15ae919325 perf(libkernel): look up the mapping with PROCMAP_QUERY in sceKernelGetModuleInfoForUnwind
On Linux every call opened /proc/self/maps and scanned it line by line with sscanf. Unity titles call it on each stack walk, and with about 900 mappings God of War Sons of Sparta (PPSA28997) spent most of its main thread there. The covering mapping is now asked of the kernel with PROCMAP_QUERY (Linux 6.11), on one descriptor opened once, as GuestMemory does; older kernels and APS5_NO_PROCMAP_QUERY keep the line scan.
2026-10-10 22:50:46 -03:00
Adrià Franch 9fe5d90cbe test(agc): split agc_driver_flat_apertures into six parts
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 03:47:10 +02:00
Adrià Franch d4b9808705 fix(libkernel_sys): keep umask bits up to 07777 like FreeBSD
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 03:36:40 +02:00
Hannah Lyons 9c38ea16cf docs: say where XashPS5 calls fork 2026-10-11 03:36:32 +02:00
Hannah Lyons 967de40393 feat(libkernel_sys): export fork and implement setsid and umask 2026-10-11 03:36:32 +02:00
Claude 7c4f9381d4
Merge upstream main into fix-shader-f16-directed-rounding
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9MzdVqDf6wHUKzNymQSze
2026-10-11 01:33:16 +00:00
raghav314 aa013f59ac fix(libc): register guest heap blocks without GPU access
AnyPS5's libc heap registered every block with GPU access, so every
address-based build imported or mirrored each malloc block the title had
made. The console's libc.prx maps its heap with protection 3 (CPU read
and write, no GPU bits), so the GPU never sees it there either.

Heap blocks are now registered without GPU access; reallocating keeps the
block's access. The AvPlayer fallback for a title that passes no texture
allocator stands in for that allocator, which hands out memory the GPU
reads, so it allocates through a new GuestHeapAlignForGpu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:02:30 +05:30
fma-rc ab0babdc9b
fix(libs): bind the system libraries eagerly on Linux
A title calls our exports on stacks it sized for the console. With lazy
binding the first call through a PLT slot runs the dynamic linker's symbol
lookup on that stack: on the 2 KiB fiber context Astro's Playroom uses it
wrote below the context into the neighbouring heap chunks.
2026-10-11 03:31:37 +02:00
Scramblrrrr 4fd6192d5c fix(agc): enforce retained-byte budget before buffer-only work 2026-10-10 22:25:59 -03:00
Adrià d31b57a4ca
Merge pull request #3208 from adriadam10/fix/agc-4444-mandatory-format
fix(agc): view 4_4_4_4 textures as B4G4R4A4, which every Vulkan device can sample
2026-10-11 03:20:57 +02:00
MarcZX100 eb9efe109e fix(libkernel): preserve vector socket error codes 2026-10-11 01:17:37 +00:00
MarcZX100 d78af2c710 fix(libkernel): route vector I/O on guest sockets 2026-10-11 01:16:58 +00:00
Dean Galvin 60f12c888d fix(agc): compare host imports when device writes reach the write watch
The import probe only checked whether a GPU read of an imported range
reports its pages as written. lavapipe runs command buffers on CPU
threads, so its writes into an import go through the page tables and
are collected as CPU stores. In agc_unit_shadow the whole publish's
copy into the import is then collected as a CPU store over unit 3, and
the next partial publish drops the slab's newer bytes as stale: "the
partial publish did not copy exactly the partly covered unit".

The probe now also fills the scratch range on the GPU and collects
again. When the read or the fill reports pages as written, host and
dma-buf imports are compared. lavapipe reports 0 of 4 pages after the
read and 4 of 4 after the fill; NVIDIA reports 0 after the fill.

The probe change is the first commit of #1046.
2026-10-11 14:15:27 +13:00
Chad 7755e1d05c fix(relinker): leave needed libraries nothing imports from out of the start-up load list
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 20:14:23 -05:00
Adrià Franch bbe26912dc fix(agc): view 4_4_4_4 textures as B4G4R4A4, which every Vulkan device can sample
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 03:13:40 +02:00
Scott Schuster 39748573b0 docs(technical-debt): record what sceKernelGetAppInfo infers
AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:11:29 +02:00
Hannah Lyons 0e88f3014d fix(libkernel): name pthread_kill's errors and test the signal range edge 2026-10-10 21:11:29 -04:00
Hannah Lyons d8af71c0ca feat(libkernel): implement pthread_kill 2026-10-10 21:11:29 -04:00
Scott Schuster 3f32c12fd8 fix(libkernel): read sceKernelGetAppInfo's title id through AppMetadata
The title id now comes from GetAppTitleId, so param.json has one parser and
its validation (a missing file or titleId throws). Another pid returns EPERM
and a null info returns 0 without writing, as shadPS4 does. app_id stays 1,
the running title's id in libSceSystemService, which is inferred, not
measured.

guest_app_info runs the call without param.json in a child process and
checks that the field between app_id and the title id is left alone.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:11:18 +02:00
Scott Schuster a6520d0c8b feat(libkernel): implement sceKernelGetAppInfo
sceKernelGetAppInfo fills the app id and the title id of the calling
process: app id 1, the running title's id in libSceSystemService, and the
titleId of /app0/sce_sys/param.json at offset 0x10, up to 9 characters and a
terminator. Only those fields are written, since callers declare the
structure with different sizes. Another pid returns ESRCH and a null info
EFAULT.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:11:18 +02:00
Adrià 77bd928a3c
Merge pull request #3201 from adriadam10/feat/libc-ctime
feat(libc): implement ctime
2026-10-11 03:06:01 +02:00
Adrià 9ba3d0d7d4
Merge pull request #3198 from adriadam10/feat/libc-rewind
feat(libc): implement rewind
2026-10-11 03:02:07 +02:00
Adrià Franch ef2d56eb9c feat(libc): implement ctime
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 02:58:30 +02:00
Dean Galvin 5543c73b37 fix(libkernel): reserve the AMM virtual address ranges at the top of the guest arena
The AMM ranges were reserved address-less on first use, so they took the
lowest free address of the arena, directly after the title's last mapping,
where the title's next hinted maps go. They are now reserved at a fixed
place, the last 64 GiB of the guest arena, which maps without MAP_FIXED and
the hints derived from them do not reach; a reservation that cannot be made
there throws.

Fixes #3146
2026-10-11 13:56:11 +13:00
Adrià Franch e7605c8fd6 feat(libc): implement rewind
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 02:54:24 +02:00
Achraf Reyani 0f480c6acc feat(libc): implement strsep
Split at the first delimiter like FreeBSD's strsep: empty fields are
returned, and the cursor becomes null after the last token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:48:07 +09:00
Achraf Reyani 86db61ca30 feat(libc): implement rand_r
Share rand's generator step with rand_r, which advances the caller's
state instead of the global one, as FreeBSD's rand and rand_r share
do_rand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:48:07 +09:00
hugodearaujo 4c4e789a33 fix(libSceRudp): match the console's init and status checks
Measured on a PS5 (firmware 13.60):
- sceRudpInit rejects a null pool or a size of 0 or less with
  INVALID_ARGUMENT, and a pool under 0xC58 bytes or not 8-byte aligned
  with MEMORY (0x80770007).
- sceRudpGetStatus rejects a null pointer or a byte count of 0 or above
  0xF8 with INVALID_ARGUMENT and reports the live context count at 0x64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:40:27 -03:00
Achraf Reyani 1191ed3eaa feat(libc): implement the hyperbolic functions
Export sinh, cosh, coshf, asinh, asinhf, acosh, acoshf and atanh,
forwarding to the C++ standard library like tanh and tanhf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:38:33 +09:00
gookie 23a8b8b3d0 perf(agc): build the initial context registers once
InitialContextRegisters built the clear-state context registers on every
call: about 200 emplace calls from its list and loops, with the register
vectors growing several times on the way to offset 0x3b8. Each
QueueState starts from it, so it ran for every CLEAR_STATE, and
ResolveShaderAbi and ResolveGraphicsStagesAbi construct a QueueState on
each call, which sceAgcLinkShaders, sceAgcCreatePrimState and
sceAgcCreateInterpolantMapping make while a title draws.

The registers are now built once into a table that is never destroyed,
so a queue cleared while the process exits still finds it, and each call
returns a copy of the table.

A call takes 71 ns instead of 746 ns, and constructing a QueueState 885
ns instead of 1378 ns (200000 calls each, GCC 13 -O2). On the title
screen of PPSA21402 (Balatro) the two functions took 44 to 47 of about
2300 CPU samples per 10 s and no longer appear in the profile.
2026-10-11 02:33:14 +02:00
gookie 132715e4e2 perf(libSceNgs2.native): parse waveform files without reading their samples
sceNgs2ParseWaveformFile read everything from the offset to the end of
the file into a zero-filled buffer and parsed that, although parsing
uses only the RIFF chunk headers and the fmt, fact and smpl payloads.
A waveform at an offset in a sound bank cost a read of the rest of the
bank on each call.

ReadChunks now takes the bytes through an accessor. Waveform data passes
its buffer; a waveform file seeks to and reads the headers and those
payloads alone, with the same checks against the length from the offset
to the end of the file. The format dispatch both use moves to
ParseWaveform.

ngs2_parse adds a bank of two waveforms in one file, the second with a
chunk after its samples, and parses each at its offset.

PPSA21402 (Balatro) parses its five 33 MB music tracks at start: one
call took 8.3 to 26.7 ms and allocated 33 MB, and now takes 0.01 to
0.04 ms with the same result.
2026-10-11 02:29:13 +02:00
Adrià 06da117642
Merge pull request #3176 from adriadam10/carry/pthread-attr-setsolosched-np
feat(libkernel): implement pthread_attr_setsolosched_np
2026-10-11 02:24:45 +02:00
Adrià 343163a0c1
Merge pull request #3174 from adriadam10/carry/system-gesture-no-touch
fix(libSceSystemGesture): report no touch events for the primitive and recognizer calls
2026-10-11 02:22:43 +02:00
Adrià f1ae427b66
Merge pull request #1337 from TibixDev/pr/cmask-fast-clears
fix(agc): keep CMASK clears resident without host imports
2026-10-11 02:13:34 +02:00
Scott Schuster 39fdc48b5f fix(agc): read unregistered graphics programs only while no shader is registered
An unregistered graphics program is read raw only while the shader registry
is empty; with shaders registered it throws, as before. A draw that uses a
raw program is noted, and RegisterShader throws once that has happened,
since a title that registers shaders after drawing unregistered programs is
not understood. The draw cache revalidates a raw program by reading it raw.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:12:14 -05:00
Adrià Franch 8d90c1f190 docs(technical-debt): list pthread_attr_setsolosched_np under unknown function info
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 02:11:41 +02:00
David 064f5ca825 feat(libkernel): implement pthread_attr_setsolosched_np
The POSIX alias takes (attr, int), returns EINVAL (22) for a null or
uninitialized attribute like the other pthread_attr setters, and
stores the value through scePthreadAttrSetsolosched, returning its
result in errno form. The signature and the stored int follow the SCE
twin in KytyPS5 and sharpemu; PS5PCEM implements the alias the same
way. The value is not applied to scheduling, recorded in TechnicalDebt.

Returnal (PPSA01285 v03.000.005) stops on it after eager binding
(#2872, #1155):

    what(): pthread_attr_setsolosched_np_nid_postfix not implemented

LEGO Horizon Adventures (PPSA14632, #734) and Palworld (PPSA23126,
#2598) import it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 02:06:30 +02:00
Adrià Franch 894ef6db09 test(libSceSystemGesture): cover the handle and null checks of every recognizer call
Moves the no-touch line to "Silent stubs" and records the error-code disagreement with KytyPS5.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 02:04:04 +02:00
Adrià 942a174e0d
Merge pull request #3015 from MarcZX100/codex/prbatch-2805-lds-lock
fix(shader): avoid spinning in the spilled LDS lock
2026-10-11 02:03:58 +02:00
Adrià e8d6de4ae7
Merge pull request #1091 from kjhq/feat/libkernel-socket-events
feat(libkernel): implement read and write events for guest sockets
2026-10-11 02:02:31 +02:00
xXPBSXx 6e2ea0a071 docs(technical-debt): list the system gesture no-touch behavior
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 02:01:32 +02:00
xXPBSXx 4bf608565f fix(libSceSystemGesture): report no touch events for the primitive and recognizer calls
WIP: the TechnicalDebt entry for the silently successful calls is still missing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 02:01:32 +02:00
Scott Schuster d1d1681bae fix(agc): drop a cached draw whose unregistered program was rewritten
The register draw key identifies an unregistered program only by its
address, and a key hit reuses the entry's decode without reading the
program again. A different program uploaded to the same address with
the same registers would run the old compiled shader. A hit now checks
the decode's unregistered programs against guest memory and drops the
entry when one changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:00:20 -05:00
Scott Schuster 7373ee1311 feat(agc): prepare unregistered graphics programs at first use
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:00:19 -05:00
Scott Schuster dddd9f29c2 test(agc): cover raw program snapshots and headerless vertex decode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:59:28 -05:00
Scott Schuster 767b8f83a2 feat(agc): accept graphics programs without an AGC shader header
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:59:28 -05:00
Adrià 2a38c0bd91
Merge pull request #3011 from MarcZX100/codex/prbatch-2988-cond-wait
fix(libkernel): return errors for waits with an unowned mutex
2026-10-11 01:59:12 +02:00
Adrià Franch 6b9f0cd01a test(agc): pass the gpu flag to GuestAllocations::Mutation::Add in the CMASK pass test 2026-10-11 01:58:31 +02:00
Adrià a0d669926c
Merge pull request #2996 from MarcZX100/fix/agc-mesh-wave32-subgroup-2815
fix(agc): require 32-lane subgroups for wave32 mesh programs
2026-10-11 01:58:20 +02:00
TibixDev 9207f7245c fix(agc): keep CMASK clears resident without host imports
Use the upstream CMASK implementation and remove the import requirement from image clears. Propagate storage-image creation failures. Test repeated clears, copied write-back, and failure without changing guest data.

AI-assisted: yes.
2026-10-11 01:57:26 +02:00
Achraf Reyani c332bdb319 test(libkernel): skip the Windows lstat link checks without the symlink privilege
guest_filesystem creates symbolic links for the Windows lstat checks.
Without administrator rights or Developer Mode, CreateSymbolicLinkW
fails with ERROR_PRIVILEGE_NOT_HELD even with
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, and the test aborted there
(reported as a stale guest errno). Skip those checks with a note in that
case; any other failure to create the first link still fails the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:56:03 +09:00
XairRrR da642e807b fix(libSceVideoOut): take 64-bit VRR peg arguments and test peg and unpeg 2026-10-11 01:55:16 +02:00
AlxcBTW 4e7511dc32 perf(shader): check f32 product tininess in one multiply to nearest even
#2839 decides f32 product tininess after rounding, in all four f32
round modes, from the exponents and a UMulHi and IMul of the
significands, and builds the flushed value from them. To nearest even,
the mode of shaders without a known float mode and of the 0xc0 most
titles use, one multiply decides it: one factor times 2^64, which is
exact below 2^64, times the other factor rounds the exact product once
to 24 bits in the normal range, and 0 < |that| < 2^-62 is tininess
after rounding. A product that rounds up to 2^-126 is then not tiny and
keeps the emitted product, which is 2^-126 there, so nothing has to be
built from the significands.

The flush of v_mul_f32 v5, v6, v7 takes 12 IR instructions instead of
34, counted as the instructions the flush select needs beyond the
product. vector_constant_factor_tininess pins 12 to nearest and 36 for
the directed path of the same instruction, and checks that the
directed modes and v_mad_legacy_f32 (before rounding) keep #2839's
check. Its round-to-nearest branches are removed as unreachable.

The f32 denormals entry says which rounding the check inherits: the
multiply is a plain OpFMul like the product, with no f32 rounding mode
requested, so it relies on the driver rounding f32 to nearest even, as
the products do. F32ConstantFactorTininess names the row a check before
rounding flushes, 0x3f7ffffe * 0x00800001, which keeps the emitted
0x00800000.

Against #2839 to nearest even, a model of both checks agrees on
1,074,977,546 operand pairs (every 24-bit significand at both rounding
thresholds, random pairs, specials) with each other and with an exact
reference. On an RTX 5070 the outputs of #2839's own tininess and
mixed-source shaders are bit-identical with either lowering over
165,298 and 164,008 generated rows in all six float modes tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:54:16 +02:00
kjhq 0abe0b832b feat(libkernel): wake socket read and write events instead of polling
A wait on an equeue that holds socket events now blocks in poll/WSAPoll on
those sockets plus a per-thread loopback wake socket, instead of rechecking
every millisecond. Adding, triggering or deleting an event and closing the
equeue wake the blocked waiters. Closing a socket removes its read and write
events, as on FreeBSD. A read event also reports EV_EOF once the peer has
shut down its sending side.
2026-10-11 01:54:15 +02:00
kjhq 9b7535c6a4 feat(libkernel): implement read and write events for guest sockets
sceKernelAddReadEvent/DeleteReadEvent and sceKernelAddWriteEvent/
DeleteWriteEvent register EVFILT_READ and EVFILT_WRITE events on guest
sockets. The equeue polls the host socket for readiness on each wait
and reports the readable byte count or the send buffer size in data,
with EV_EOF on hang-up or error.
2026-10-11 01:54:04 +02:00
Adrià e28fbc277d
Merge pull request #3010 from MarcZX100/codex/prbatch-2998-strerror
fix(libc): match FreeBSD errno message strings
2026-10-11 01:53:29 +02:00
MarcZX100 324be50c64 docs(libkernel): record condition wait errors 2026-10-11 01:53:27 +02:00
Hussein Kadhim 709c12e133 fix(libkernel): return EPERM or EINVAL when a condition wait gets a mutex the caller does not hold
pthread_cond_wait and pthread_cond_timedwait, and their sce counterparts, threw a
host exception when the mutex was unlocked, locked by another thread, or not yet
initialized, and dereferenced the adaptive static initializer. FreeBSD returns
EPERM for these (EINVAL for a destroyed mutex) before touching the condition.

(cherry picked from commit a78bb8a855ca3b277f128c6a9e52ff3949b9cb80)
2026-10-11 01:53:12 +02:00
ThatsLeo a2d82815b3 fix(shader): take the LDS lock with one attempt per loop iteration
The elected lane's inner spin loop never ended on Mesa ANV with the LDS in
a storage buffer. It now tries once and the outer loop elects again; the
update is unchanged.

(cherry picked from commit e894f9092326a849ebe1ce46ff0ed3b25fbb7e9b)
2026-10-11 01:52:59 +02:00
XairRrR 9021735022 feat(libSceVideoOut): accept VRR peg and unpeg on a fixed-rate output
sceVideoOutVrrPegToFixedRate and sceVideoOutVrrUnpegFromFixedRate were
NotImplemented without arguments. Both take the output handle; the peg
also takes two further arguments whose meaning is unknown. VRR is not
modelled and the output always runs at a fixed rate, so both validate
the handle and return 0; non-zero peg arguments throw. Recorded in
TechnicalDebt.

Uncharted: Legacy of Thieves Collection (PPSA05684) stops on main with
"sceVideoOutVrrUnpegFromFixedRate not implemented"; it passes its
output handle to both (and zeros to the peg) and ignores the results.
2026-10-11 01:52:10 +02:00
Adrià ed79bde5b9
Merge pull request #2987 from CouchRiv/fix-shader-f16-addmul-denorm-flush
fix(shader): flush scalar f16 add/mul/sub denormals to signed zero
2026-10-11 01:51:46 +02:00
Adrià 9d792ae477
Merge pull request #2989 from CnRJay/fix/srt-null-root-reads
fix(recompiler): read SRT words through a null user-data pointer as zero
2026-10-11 01:49:13 +02:00
Adrià 9402d32fc2
Merge pull request #2993 from CnRJay/fix/agc-indirect-getsize-count
fix(agc): ignore the count passed to the indirect register GetSize functions
2026-10-11 01:48:56 +02:00
Adrià 62419286cd
Merge pull request #3009 from MarcZX100/fix/libkernel-open-directory-3004
fix(libkernel): report ENOTDIR for Windows O_DIRECTORY opens
2026-10-11 01:48:46 +02:00
Adrià 935993d608
Merge pull request #2980 from JAB-dev/test/agc-draw-cache-reuse
test(agc): require a repeated draw to reuse the cached draw
2026-10-11 01:46:52 +02:00
Adrià b64c75fc12
Merge pull request #2939 from CnRJay/fix/agc-dcc-comp-to-single
fix(agc): expand comp-to-single DCC keys in a DCC decompress pass
2026-10-11 01:46:49 +02:00
Adrià abb2f8e4fc
Merge pull request #2986 from MarcZX100/fix/relinker-windows-unicode-2640
fix(relinker): support Unicode Windows startup paths
2026-10-11 01:46:23 +02:00
Adrià 30ab2f6ef5
Merge pull request #2990 from CnRJay/fix/agc-dispatch-ahead-indirect-arguments
fix(agc): stop the dispatch look-ahead before indirect arguments an earlier dispatch may write
2026-10-11 01:46:17 +02:00
Adrià c633e6d532
Merge pull request #2880 from SleglJan/fix/shader-log2-near-one
fix(shader): correct v_log_f32 near 1.0 when the driver's log2 strays from a series
2026-10-11 01:46:08 +02:00
Adrià f336979f3b
Merge pull request #2991 from CnRJay/fix/agc-nop-one-dword
fix(agc): encode a one-dword NOP as the header-only form
2026-10-11 01:46:02 +02:00
Adrià 5bd6912b0b
Merge pull request #2978 from MarcZX100/fix/libkernel-rwlock-destroy-busy
fix(libkernel): return EBUSY when destroying a held rwlock
2026-10-11 01:45:28 +02:00
Adrià 68afb3cbb7
Merge pull request #2976 from SleglJan/fix/agc-drain-registration-prepare
fix(agc): drain the registration preparation pool before the device is reset
2026-10-11 01:44:40 +02:00
Adrià 59a8cbab89
Merge pull request #2981 from MarcZX100/codex/system-service-language-2769
feat(libSceSystemService): select the console language
2026-10-11 01:43:53 +02:00
Adrià 3db065af86
Merge pull request #2984 from MarcZX100/fix/agc-ignore-unchanged-watched-blocks
fix(agc): ignore unchanged imported texture blocks
2026-10-11 01:43:27 +02:00
Adrià 71d5f63018
Merge pull request #2912 from TheAggie/fix/agc-strided-buffer-overhang
fix(agc): bound a strided buffer's rounded-up last record by its allocation
2026-10-11 01:42:57 +02:00
overlordxrz-source c447b289ca fix(shader): read 2D-array T#s through 3D image accesses
Since #2133, a 3D image_sample_lz or image_load bound to a 2D-array T#
decodes as 2D and matches the new 2D mode, so it reads layer 0 for any
r and returns zero for z != 0. adriadam10 measured on RDNA2 (gfx1035)
that dim 3D on a 2D-array T# behaves exactly like dim 2D-array, with r
or z as the layer. Decode a 2D-array T# bound to a 3D access as 2D-array
and add a 2D-array mode next to the 2D one.

The same measurement covers image_load_mip on both T# types and
image_get_resinfo, which returns (w, h, 1, levels) on a 2D T# and
(w, h, layers, levels) on a 2D-array T#. Allow those accesses and return
1 as the third resinfo component through the 2D mode. image_get_lod is
not measured and keeps throwing.
2026-10-10 23:42:50 +00:00
poonasor 1d7f8bd365 fix(agc): keep a shader library part's modules until the part is destroyed
Pipeline destroyed its shader modules right after LinkPipelineFromLibraries returned, while the pre-rasterization and fragment shader library parts built from them stay cached and are relinked later with VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT. On AMD's Windows driver (RX 6700 XT, Adrenalin 25.10.45.05) that link faults inside amdvlk64.dll at varying offsets, reading freed heap memory, in 22 agc tests on a cold driver cache; all of them pass with APS5_NO_PIPELINE_LTO=1. Running the optimized link synchronously or without a pipeline cache did not help, keeping the modules alive did.

When the optimized link is enabled, the library store takes over the modules of each newly built shader part and destroys them in ClearPipelineLibraries after the pending links have finished. Modules of a pipeline whose parts were all cached are destroyed as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:42:44 +02:00
Adrià 07e6ab0602
Merge pull request #2974 from MarcZX100/fix/structural-dominance-control-flow
test(shader): use structural dominance in CFG checks
2026-10-11 01:42:14 +02:00
Adrià cf70000356
Merge pull request #2979 from MarcZX100/fix/progress-nonvoid-stub-wrappers
fix(tools): detect non-void stub wrappers
2026-10-11 01:41:43 +02:00
Adrià 6dcfc5b646
Merge pull request #2765 from TheAggie/feat/libc-alarm
feat(libc): implement alarm
2026-10-11 01:40:26 +02:00
Adrià Franch 9678b46d8b docs(technical-debt): state the key range comp-to-single uniformity is judged over 2026-10-11 01:38:32 +02:00
Chad b89b7f953c fix(agc): expand comp-to-single DCC keys in a DCC decompress pass
Key 0x10 (GFX9_DCC_CLEAR_SINGLE in Mesa) marks a 256-byte block whose texels all equal its first texel. A CB DCC decompress pass over uniform comp-to-single keys now writes that texel over its block and stores uncompressed keys; a fast-clear eliminate over them throws.
2026-10-11 01:38:27 +02:00
Adrià Franch c9d1dbe6ed docs(debt): record rwlock destroy EBUSY choice 2026-10-11 01:37:32 +02:00
Zayd Zaari 718eb9cc3e fix(libkernel): return EBUSY when destroying locked rwlock 2026-10-11 01:37:26 +02:00
Adrià Franch 1e1554c768 docs(technical-debt): record the strided buffer overhang clamp 2026-10-11 01:37:01 +02:00
Scott Schuster dc48c61050 test(agc): a strided buffer's rounded-up last record stays within its own allocation
When another readable allocation starts right after the buffer's allocation,
the bound range still ends at the first allocation: the bytes past it are
outside the buffer the descriptor's records describe, and binding into the
neighbour would send the range back to a copy on every draw.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:37:00 +02:00
Scott Schuster b352406f70 fix(agc): bound a strided buffer's rounded-up last record by its allocation
RADV rounds a strided buffer descriptor's record count up, so stride * records
can run up to one stride past the end of the buffer's allocation. The guest
buffer region then no longer fits inside the allocation's host import and is
copied on the CPU, whole, for every draw that binds it.

When a strided descriptor ends less than one stride past the end of the
readable registered allocation that contains its base, the range is bound up
to the allocation's end. RetroArch's Dolphin core binds a 48 MiB stream buffer
with stride 20 (records 0x266667, 12 bytes past the allocation) on every draw.
With this change the buffer is bound in place from its import.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:37:00 +02:00
xXPBSXx 6825e02372 fix(agc): ignore the window offset enable bit of the raster mode
The window offset register is already required to be zero, so the enable bit has no effect on a draw that gets this far.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 01:35:53 +02:00
Adrià c07638834d
Merge pull request #2941 from CnRJay/fix/recompiler-selection-merge-loop-escape
fix(recompiler): merge a loop selection whose arm leaves the iteration where its arms rejoin
2026-10-11 01:35:31 +02:00
Adrià 6d71420c69
Merge pull request #2938 from MarcZX100/fix/agc-resize-idle-on-recreate
fix(agc): drain the device only when the swapchain is recreated
2026-10-11 01:35:27 +02:00
Adrià 29083579f4
Merge pull request #2873 from CouchRiv/fix-shader-div-scale-denorm-flush
fix(shader): flush v_div_scale_f32 input denormals
2026-10-11 01:35:02 +02:00
Daan Dehing 2dd453dae0 fix(agc): drain the registration preparation pool before the device is reset
Background registration preparations (#2583) copy the device's
SpirvTarget, whose capability and extension spans point into the
device's shader profile. Driver::stop reset the device without waiting
for the detached pool, so a preparation still queued or running read
freed extension names and agc_driver crashed at exit on RADV.

Driver::stop now closes the pool after joining the queue workers: it
stops queueing and waits until no task is queued or running. A
preparation submitted after that runs on the caller's thread, which
holds its own reference to the device, like the existing fallback for
a pool without threads.

Fixes #2891

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:34:05 +02:00
Adrià Franch 3983f16e37 docs(technical-debt): v_log near 1.0 bound from the exhaustive band sweep
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 01:33:54 +02:00
Jan Šlégl 447f3a5080 docs: note the unconditional log2 series and its f16 path
v_log_f16 is lowered through the same f32 log2, so the entry names both
and states the f16 effect measured over every f16 input (one NVIDIA
result moves onto the hardware's bits, none on RADV). The series is
chosen with OpSelect, so its cost applies to every v_log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-11 01:33:44 +02:00
Jan Šlégl 580ac08478 fix(shader): correct v_log_f32 near 1.0 when the driver's log2 strays from a series
The driver's Log2 has an absolute error that does not shrink with the
result, so near 1.0 the relative error explodes: on an RTX 3080, v_log_f32
of 1 - 2^-24 is 23,947,836 ULP off. Measured on RDNA2 (gfx1036), the
hardware's log2 is within 1 ULP of the correctly rounded value, and an
eight-term series in x - 1 is within 2 ULP of both for |x - 1| <= 1/8.

The lowering keeps the driver's Log2 and takes the series only inside that
band when the two differ by more than 4 ULP, so RADV's native result stays
bit-exact and NVIDIA's is within 6 ULP inside the band.
agc_driver_log_near_one pins 64 inputs per type from the oracle with
per-lane tolerances.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-11 01:33:44 +02:00
Adrià 383851643f
Merge pull request #2940 from CnRJay/fix/recompiler-sdwa-cvt-f16-16-byte-source
fix(recompiler): accept SDWA byte sources on v_cvt_f16_u16 and v_cvt_f16_i16
2026-10-11 01:33:36 +02:00
Adrià 76e9fd3a89
Merge pull request #2922 from XairRrR/fix/graphics-interface-diagnostic
fix(agc-driver): list both stages' interfaces when graphics interfaces disagree
2026-10-11 01:31:38 +02:00
Adrià 2cae6cc3cd
Merge pull request #2917 from XairRrR/feat/agc-prepare-unpredicted-variants
feat(agc-driver): prepare shader variants registration did not predict
2026-10-11 01:31:32 +02:00
Adrià ad3369236d
Merge pull request #2920 from XairRrR/fix/runtime-image-mode-diagnostic
fix(recompiler): describe the descriptor and modes when no runtime image mode matches
2026-10-11 01:30:51 +02:00
Adrià 1be7c79336
Merge pull request #2921 from XairRrR/fix/guest-buffer-view-bounds-diagnostic
fix(agc-driver): name the view and owner bounds when a guest buffer view exceeds its GPU owner
2026-10-11 01:30:43 +02:00
Adrià d962de918a
Merge pull request #2916 from XairRrR/feat/agc-8-8-swap-alt
feat(agc-driver): render to COLOR_8_8 targets with SWAP_ALT
2026-10-11 01:30:20 +02:00
Adrià 181420f881
Merge pull request #2915 from XairRrR/fix/spirv-shuffle-struct-extracts
fix(recompiler): fold extracts into a vector shuffle only between vectors
2026-10-11 01:23:07 +02:00
Adrià 1e52f94ea1
Merge pull request #3147 from SleglJan/feat/libc-realpath
feat(libc): implement realpath
2026-10-11 01:22:38 +02:00
Adrià b7bbe45f32
Merge pull request #2913 from MarcZX100/codex/libc-opendir-eloop-db343
fix(libc): report ELOOP from opendir symlink loops
2026-10-11 01:21:40 +02:00
Adrià 4b9f07519c
Merge pull request #2864 from MarcZX100/fix/agc-release-deferred-imports
fix(agc): release retired imports while waiting for pins
2026-10-11 01:21:06 +02:00
Adrià 2b5d119fc5
Merge pull request #3138 from MarcZX100/codex/carry-font-script-3125
feat(font): retain script language and typographic design settings
2026-10-11 01:19:31 +02:00
Adrià 7d294690e2
Merge pull request #2856 from CouchRiv/fix-agc-shared-code-two-headers
fix(agc): retain registered headers sharing shader code
2026-10-11 01:18:38 +02:00
MarcZX100 890169e094 feat(libc): implement memrchr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:16:53 +02:00
Adrià 53924632bb
Merge pull request #2675 from husseinkad/fix/lds-atomic-mixed-width-lock
fix(shader): LDS 32-bit atomics take the workgroup lock of the program's 64-bit LDS atomics
2026-10-11 01:15:44 +02:00
Alex cf637814eb fix(shader): flush v_div_scale_f32 input denormals
Enable the existing input-only f32 flush policy for division scaling.
RDNA2 measurements pin all three sources and signed zeros; keep the
scaling rules unchanged and retain their separate technical debt.

Co-Authored-By: Codex gpt-6.1-sol <noreply@openai.com>
2026-10-11 01:14:31 +02:00
Adrià 5b4709f283
Merge pull request #3140 from MarcZX100/codex/carry-dialogs-3107
feat(dialogs): run G2P and VR setup dialogs without UI
2026-10-11 01:14:15 +02:00
Adrià aa79dbdfe3
Merge pull request #2885 from MarcZX100/fix/relinker-linux-input-phdr-interp
fix(relinker): drop input Linux PT_PHDR and PT_INTERP
2026-10-11 01:13:32 +02:00
Adrià df52ac8354
Merge pull request #2898 from MarcZX100/fix/libkernel-windows-lstat-reparse
fix(libkernel): detect Windows reparse points in lstat
2026-10-11 01:13:25 +02:00
Adrià a75c0c5759
Merge pull request #1430 from fisherjoey/fix/depth-surface-record
perf(agc): prove sampled depth surfaces in the fast resource proof
2026-10-11 01:12:49 +02:00
Jan Šlégl e1f168a24d feat(libc): implement realpath
Resolves a guest path the way FreeBSD 11's realpath does: a relative
path starts from the guest working directory, "." and empty components
are skipped, ".." drops the last component and never climbs above "/",
every other component must exist, and one that is not a directory with
anything after it is ENOTDIR. Backslashes separate components as in the
rest of the path layer. The result is the guest path; the host is
consulted only for existence and type, so host symlinks are followed but
not expanded, and ".." is lexical, as in the rest of the path layer. A
null buffer is PATH_MAX bytes from the application heap, a null path is
EINVAL, an empty one ENOENT, and 1024 bytes or more in the input or the
result is ENAMETOOLONG. On failure the caller's buffer holds the path
that failed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-11 01:11:33 +02:00
Adrià 0d2546e87f
Merge pull request #2876 from CouchRiv/fix-shader-minmax-f16-denorm-flush
fix(shader): flush f16 min/max denormal inputs
2026-10-11 01:10:52 +02:00
Adrià 14bb70878e
Merge pull request #2875 from CouchRiv/fix-shader-div-fmas-nan-ieee
fix(shader): follow IEEE_MODE in v_div_fmas_f32 NaN selection
2026-10-11 01:10:28 +02:00
Adrià c7375433e9
Merge pull request #2838 from MarcZX100/fix/sdwa-cvt-f16-u16-byte-sources-2747
fix(recompiler): accept byte source selectors on v_cvt_f16_u16 SDWA
2026-10-11 01:07:03 +02:00
Adrià Franch 946158a503 docs(architecture): describe the per-code header registry
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 01:04:50 +02:00
Alex fb45627bb7 fix(agc): retain registered headers sharing shader code
Keep each registered header and its prepared shader state instead of
replacing every registration for the same code address. Resolve explicit
ABIs by header and programs by type, preserving re-registration order.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
2026-10-11 01:04:43 +02:00
Scott Schuster e5ae8dfcb0 fix(libkernel): keep the alarm state alive until the process exits
The detached alarm thread waits on a condition variable that was a
namespace-scope static. At exit its destructor ran with the thread still
waiting, and glibc's pthread_cond_destroy blocks then, so a process that
called alarm never exited on Linux. The mutex, condition variable, deadline
and started flag now live in one structure allocated once and never
destroyed.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:04:35 -05:00
XairRrR 70d7aa58e3 perf(agc-driver): import adjacent registered ranges as one host-import span
A host import covered exactly one registered range, so a buffer crossing
two ranges had no import and was copied on the CPU at every use, under
the GPU mutex. Titles that map a GPU heap piece by piece (Uncharted maps
1 MiB direct-memory pieces) hit this for every buffer larger than a
piece.

An import now covers the run of address-adjacent registered ranges that
are readable with the same write and GPU access. Runs never overlap, so
imports do not either; an import is retired when any range of its run
changes, and a refused run is remembered by its base. Callers already
address imports relative to their base.
2026-10-11 01:04:12 +02:00
Adrià Franch 1d298ad8b4 docs(debt): list the font script/typographic setters under Unknown function info
Their signatures are inferred from SharpProspero only, so the line belongs
with the other unverified signatures and not at the end of Silent stubs.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 01:03:58 +02:00
Abdulrahman Elkordy 5ea89c7d4c feat(font): keep a handle's script languages and typographic features
sceFontSetScriptLanguage, sceFontGetScriptLanguage,
sceFontSetTypographicDesign and sceFontGetTypographicDesign threw. With
the signatures SharpProspero declares, a font handle now keeps the
language set for each script and the feature set for each typographic
design, under the handle's lock, and returns them, with 0 for one never
set. They do not change shaping or rendering yet; TechnicalDebt records
the assumptions.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
(cherry picked from commit c4dcbe4403dc635fde2a823dec311a939816cefc)
2026-10-11 01:03:52 +02:00
MarcZX100 f5618d9124 fix(agc): release retired imports while waiting for pins 2026-10-11 01:01:14 +02:00
Scott Schuster 383bffd8c7 feat(libc): implement alarm
RetroArch (PPSA99169) stops at alarm on main: `FAIL: unresolved ELF import DQXJraCc1rA from libSceLibcInternal.prx`.

alarm(seconds) arms one process-wide real-time alarm and returns the seconds left on the previous one, rounded up like FreeBSD's alarm.c (any partial second counts); alarm(0) cancels it. When it expires, SIGALRM's disposition as recorded by sigaction or signal applies: ignored, nothing happens; default, the process terminates as on FreeBSD (exit status 128 + 14); a guest handler throws, because asynchronous delivery to a guest handler is not implemented.

The timer lives in libkernel next to the signal dispositions (GuestAlarm_nid_no_patch); libSceLibcInternal, which the titles import alarm from, forwards to it.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:59:58 -05:00
Adrià 64baa79b65
Merge pull request #2770 from Yuva1024/fix/avplayer-unsynced-test-autostart
test(avplayer): stop the unsynced test racing the player's auto-start
2026-10-11 00:59:44 +02:00
Adrià 3099003f02
Merge pull request #2846 from MarcZX100/fix/write-watch-thread-test-starvation
test(libc): keep macOS write watch stress bounded
2026-10-11 00:58:50 +02:00
xXPBSXx aace6a3f38 fix(libkernel): report the largest free direct memory block from sceKernelAvailableDirectMemorySize
The call returned the first free gap in the range instead of the largest free block.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 00:58:28 +02:00
Adrià e4045bbbbe
Merge pull request #2839 from CouchRiv/fix-shader-tininess-after-rounding
fix(shader): detect f32 tininess after rounding when flushing products
2026-10-11 00:57:20 +02:00
xXPBSXx 272b9d1338 test(relinker): check Windows TLS thread pointer offset
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 00:56:01 +02:00
xXPBSXx 8e03bb0af8 fix(relinker): place the Windows thread pointer after the TLS size rounded to its own alignment
The converted thread pointer was set to the TLS block plus the size rounded to max(p_align, 16), while the guest reads its first variable at tp minus the size rounded to p_align. For a PT_TLS with memsz 0x21 and p_align 8 (Resident Evil 4) that is 0x30 against 0x28, so the first variable was read from the second slot. The thread pointer now uses the size rounded to p_align; the block layout is unchanged. WIP: the test for this is still missing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 00:56:01 +02:00
Get-fix 9a13dc8c78 fix(relinker): stop code scans at the PLT in executables with PT_SCE_DYNLIBDATA
A PS4 executable (CUSA00900) keeps 37 MiB of read-only data in its
executable segment after the code. The syscall scan and the call-site
resolution decoded the whole segment linearly, reached a float table and
failed with "Unsupported 0F 79 opcode without SSE4A prefix". In
executables with a PT_SCE_DYNLIBDATA segment they now stop at the end of
the PLT that follows the last function of the unwind table. The PLT is
found by searching forward from that function for its first entry, which
pushes the GOT entry at PLTGOT + 8 and jumps through PLTGOT + 16, since
code without unwind entries can sit in between (680 bytes of start-up
code in an OpenOrbis-built sample). When the executable has PLT
relocations and no such entry follows, the relinker fails instead of
guessing. Executables without the segment are scanned as before.

(cherry picked from commit a21e8fe4c0e6c03189d559e992c0f037c076700d)
2026-10-10 22:53:48 +00:00
Abdulrahman Elkordy 2a92eaa351 feat(libs): run the G2P and VR setup dialogs as common dialogs without UI
libSceCdlgG2P and libSceVrSetupDialog threw from every export. They now
run the common-dialog state machine libSceLoginDialog uses: Initialize,
Open, the status calls, GetResult, Close and Terminate follow it, the
dialog finishes at Open without showing anything, and GetResult reports
that the user cancelled, writing only the leading int32 result. The
signatures are assumed from the other common dialogs, as TechnicalDebt
records. 13 exports move from stubs to implemented.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
(cherry picked from commit 07992adf80bae9b2d7da4b751cd21c040fa1c5b8)
2026-10-10 22:53:48 +00:00
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égl 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 <noreply@anthropic.com>
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.maia 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 <noreply@anthropic.com>
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
David 9277d06705 feat(libc): implement the Dinkumware mutex and condition exports
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
Chad 879188b172 ci: re-run flaky macOS write_watch_threads timeout
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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égl 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 <noreply@anthropic.com>
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
PhialsBasement 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 <noreply@anthropic.com>
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
Adrià Franch d731f5034e test(agc): pass the gpu argument to GuestAllocations::Mutation().Add
Co-authored-by: orishamir <orishamir@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 00:33:12 +02:00
MathiasDevelopes 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZHkb8kUwnHAuBBbHywvJf
2026-10-11 00:33:07 +02:00
MathiasDevelopes 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZHkb8kUwnHAuBBbHywvJf
2026-10-11 00:33:07 +02:00
MathiasDevelopes 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 <noreply@anthropic.com>
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
raghav314 be1f501525 fix(agc): import GPU-mapped guest memory when it is mapped
The registry calls an observer on the mapping thread, after the registry
lock is released, with the ranges a kernel mapping gave GPU access:
direct and flexible maps with it, and fixed remaps with it over a
registered range (a reservation). The mutation looks them up while it
still holds the lock and hands them over weakly, with the registry
generation it ended at, so the observer does not keep a range alive.
The driver imports those ranges on its current device, so an
address-based build finds the import instead of pinning the memory on
the queue that first uses it. A range that gains GPU access through
sceKernelMprotect, and AnyPS5's own libc heap, are still imported on
first use.

The import at map does not reconcile the other imports with the
registry, so its cost does not grow with the number of imports. It skips
a range that is gone, and any range when the imports were reconciled
with a newer registry since; the next lookup imports those as before.
It installs the pin waiter as the other import paths do, so unmapping a
range imported at map retires its import. The live import bytes are kept as a
running total instead of being summed over every import. Once the import
table belongs to the current device the import takes only the table's
lock; the first import on a device (which runs the write-watch probe)
and a device that was just replaced go through the GPU lock. Clearing
the observer waits for calls already running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:23:23 +02:00
Joey Fisher a8c4f86b46 fix(agc): limit the depth surface fast proof to plain 2D lookups
Array and layered depth views go back to the full walk, so a lookup that
refreshes array slices is not skipped by the fast proof.
2026-10-11 00:22:51 +02:00
Joey Fisher cdf303ea4b test(agc): prove a set sampling a depth surface on the fast path 2026-10-11 00:22:51 +02:00
Joey Fisher 2828fdc8c6 perf(agc): prove sampled depth surfaces in the fast resource proof 2026-10-11 00:22:51 +02:00
Renan Pires 2d206e31bb feat(libScePad): export scePadVrControllerReadState 2026-10-10 19:21:32 -03:00
Adrià a3c43ad20f
Merge pull request #1739 from Sanjaysrinivas/test/pthread-cancel-recovery
test(libkernel): cover cancellation recovery for #1668
2026-10-11 00:20:59 +02:00
Adrià 5da6096c2a
Merge pull request #3104 from babyhuey/feat/libkernel-sync
feat(libkernel): implement sync
2026-10-11 00:20:28 +02:00
Adrià b65d6b71be
Merge pull request #1190 from MichonGoddijn231849/feat/flat-shared-private-apertures
feat(recompiler): FLAT addresses in the shared and private apertures reach LDS and scratch
2026-10-11 00:18:33 +02:00
Josip Parlov 9968fda961 docs(npmanager): name ZVZ++68nNI8 sceNpGetSandboxInfo (throwing stub), imported by PPSA28416 2026-10-11 00:15:48 +02:00
Adrià 3c46fa6f4a
Merge pull request #3078 from MarcZX100/codex/carry-3048-fcntl
feat(libkernel): implement sceKernelFcntl
2026-10-11 00:15:30 +02:00
Adrià a883f22f1c
Merge pull request #1157 from alfalfa-star/perf/agc-dma-copy-host-memory
perf(agc): sync only the source for DMA_DATA copies into host-only memory
2026-10-11 00:14:46 +02:00
Adrià Franch 36ffda9a98 test(relinker): check the declared-host import by membership, not as the module's only import 2026-10-11 00:14:26 +02:00
john.maia 5f4a28c2bc fix(relinker): keep Linux imports declared from host modules off guest exports
On Linux every executable or guest-module import whose NID a guest
module exports was renamed to the guest-suffixed name, whatever module
the import declares. A title that bundles a module exporting system
NIDs then had those imports bound to it: the libc.prx loader shim of
ps5-native-app-boilerplate exports placeholder functions under the
libSceLibcInternal NIDs, so DOOM PPSA99666's snprintf, vsnprintf,
memcpy and malloc (declared from libSceLibcInternal) returned 0 and the
title never found its WAD (#1497).

An import now binds to a guest export only when the module it declares
is a guest module, as on Windows. Imports without import-module
metadata keep the previous behaviour, and a title's own libc.prx
imported from libc still binds to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:14:19 +02:00
Hannah Lyons 97e81c4224 feat(libkernel): implement sync 2026-10-10 18:12:21 -04:00
Achraf Reyani 373670294e fix(opus): export the libSceOpusCeltDec module
ProsperoRadio (PPSA99001) imports six sceOpusCeltDec functions from
libSceOpusCeltDec and fails to load because no such module exists. It
opens this decoder only as a fallback when libSceOpusDec reports a
retryable error for a CELT packet, which libSceOpusDec here never
returns, so the module is exported without an implementation and each
function throws if it is called, as for sceSaveDataCancel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:10:03 +09:00
Adrià 2b831510be
Merge pull request #3080 from MarcZX100/codex/carry-3071
feat(libSceAmpr): implement Dinkumware thread helpers
2026-10-11 00:07:57 +02:00
Adrià Franch df25847fca fix(test): pass the gpu argument to GuestAllocations::Add in FlatApertures 2026-10-11 00:06:53 +02:00
Michon f4f05d2e6a fix(recompiler): flat apertures are 4 GB windows; an aperture access past the end is dropped whole
Measured on RDNA2 (gfx1035) in review:
- the shared and private apertures are 4 GB windows (the gfx9+ layout of kfd_flat_memory.c), so a flat
  address routes by its whole high dword, 0x80000000 or 0x70000000, not by its top 16 bits;
- a dword or short access whose last byte is past the end of LDS reads 0 or writes nothing as a whole;
  multi-dword accesses are checked per dword.
The aperture test gets rows that straddle and pass the end of LDS; the TechnicalDebt line names the
public source of the layout and keeps only the PS5's base values as inferred.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 00:06:44 +02:00
Michon 41144bea53 fix(recompiler): multi-dword FLAT stores route the shared and private apertures
Main's StoreAddressU32x2..x4 (one BDA lookup per wide store, b95842597) bypassed the aperture routing:
a flat_store_dwordx2 into the shared aperture went to BDA at 0x8000000000000000 and LDS kept its old
value. The wide store now stores each component through the aperture like the 32-bit store, and keeps
the single BDA lookup outside the apertures.

The aperture test's V# word 3 is 0x31016fac (OOB_SELECT 3, raw), as in main's other execution tests:
with OOB_SELECT 0 its output buffer read as out of range after #639, which was the failure reported on
four drivers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 00:06:44 +02:00
Michon c35f29b6be fix(recompiler): every FLAT access kind routes the shared and private apertures; table test
Sub-dword stores and unaligned dword accesses go byte-wise; 32- and 64-bit FLAT atomics
route to LDS (64-bit under the workgroup lock), scratch (read-modify-write) or BDA.
agc_driver_flat_apertures covers them in 121 rows, with mixed-address waves and wave64.
The aperture bases and the unmodelled operands 235-238 are listed as inferred.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 00:06:43 +02:00
Michon 6a1301f329 feat(recompiler): FLAT addresses in the shared and private apertures reach LDS and scratch
A compute FLAT access whose address has the console's shared aperture in its high dword (0x8000xxxx)
reads or writes the workgroup's LDS at its low dword, and one in the private aperture (0x7000xxxx)
the lane's scratch; other addresses stay guest memory through BDA. GTA V's ray traversal keeps its
stack in LDS and spills it to scratch through such addresses; treated as guest memory the pushes were
lost and the traversal never ended (device lost). An execution test round-trips both apertures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 00:06:34 +02:00
David 9902f137af feat(libkernel): implement sceKernelFcntl
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit f0c649704dbf0b84077c29ea914e0e4799714fe1)
2026-10-11 00:06:02 +02:00
Adrià 0de1dfdff8
Merge pull request #3046 from MarcZX100/codex/libc-secure-format-scan-3032
feat(libc): implement vsnprintf_s and vsscanf_s
2026-10-11 00:05:28 +02:00
Adrià 61a85df9d4
Merge pull request #2865 from babyhuey/feat/posixforwebkit-arc4random-buf
feat(libScePosixForWebKit): implement arc4random_buf
2026-10-11 00:05:00 +02:00
Adrià 685905b67c
Merge pull request #3006 from babyhuey/feat/libsceaudioin-init
feat(libSceAudioIn): export sceAudioInInit
2026-10-11 00:04:53 +02:00
Adrià b680612fbb
Merge pull request #2967 from babyhuey/feat/libscelibcinternal-utime
feat(libSceLibcInternal): implement guest utime
2026-10-11 00:03:19 +02:00
Adrià d3f9dd07e6
Merge pull request #2968 from babyhuey/feat/libc-hostname
feat(libc): implement guest gethostname
2026-10-11 00:02:54 +02:00
Adrià Franch fddcb00a40 fix(libSceAmpr): give _Thrd_sleep the console signature and move its TechnicalDebt line
The title's libc.prx _Thrd_sleep takes a second xtime* (remaining) and returns int.
The TechnicalDebt entry no longer sits at the end of its section.
2026-10-11 00:01:46 +02:00
Adrià ecafb64f28
Merge pull request #3083 from MarcZX100/codex/carry-3077-wide-conversions
feat(libc): implement Dinkumware wide conversion exports
2026-10-11 00:01:31 +02:00
David b446119c76 feat(libSceAmpr): implement the Dinkumware thread, sleep and spin lock exports
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-11 00:01:28 +02:00
Adrià d9dc6614e0
Merge pull request #3081 from MarcZX100/codex/carry-1578-flockfile
feat(libc): implement flockfile and funlockfile
2026-10-11 00:00:53 +02:00
MarcZX100 97ae394037 fix(test): create isolated video out fixture 2026-10-10 21:58:20 +00:00
Adrià dc105f8abf
Merge pull request #2973 from babyhuey/feat/libkernel-rwlockattr
feat(libkernel): implement pthread_rwlockattr_init and pthread_rwlockattr_destroy
2026-10-10 23:53:36 +02:00
Adrià bdfcf3d75d
Merge pull request #2932 from AchrafReyani/feat/libc-atol-atoll
feat(libc): implement atol and atoll
2026-10-10 23:53:28 +02:00
Adrià c051e83c4e
Merge pull request #3005 from babyhuey/feat/libkernel-preadv
feat(libkernel): implement preadv and pwritev
2026-10-10 23:52:58 +02:00
Adrià Franch db2743e377 docs(technical-debt): describe the vsnprintf_s/vsscanf_s constraint behaviour as implemented 2026-10-10 23:52:18 +02:00
MarcZX100 4d537755e9 test(libc): cover vsscanf_s capacity limits 2026-10-10 23:52:11 +02:00
pushkarreddyy e251de849d feat(libc): implement vsnprintf_s and vsscanf_s
(cherry picked from commit 4ca866ea3b989da6947ad110f4d6c7f4efbe27c8)
2026-10-10 23:52:11 +02:00
Adrià 5a8844676c
Merge pull request #2995 from CnRJay/feat/agc-branch-patch-target-0300
feat(agc): implement sceAgcBranchPatchSetThenTarget_0300 and SetElseTarget_0300
2026-10-10 23:52:01 +02:00
Hannah Lyons 92c9296ae3 feat(libc): implement flockfile and funlockfile
(cherry picked from commit d32eaf181aadf79efc4199b22591f1f5f228d00c)
2026-10-10 21:49:58 +00:00
David 51fca3cec3 feat(libc): implement _WStoul, _Iswctype and swscanf_s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 23:44:00 +02:00
David 63cce467e7 fix(libc): stop strtol at a 0x prefix without hex digits on Windows
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 23:40:19 +02:00
David b69fba6a15 fix(libkernel): remove read-only directories with rmdir on Windows
(cherry picked from commit da6889627a417df433802a45a8fcca58a6cb904f)
2026-10-10 21:14:34 +00:00
MarcZX100 71ced93893 test(shader): exercise the structurizer dominance regression
(cherry picked from commit 03ed5aecb241d0347b38690c49c7c8d0db9ff417)
2026-10-10 20:44:14 +00:00
MarcZX100 c5c34ad9e0 test(shader): use structural dominance in CFG checks
(cherry picked from commit c6d9f9cbed1aea7dcc66b494dd24c8ed2920b09a)
2026-10-10 20:44:14 +00:00
Scott Schuster ce98a61a83 feat(libkernel): implement pthread_set_name_np
pthread_set_name_np renames through scePthreadRename; a null name clears it,
as in FreeBSD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:41:36 -05:00
Alex 43ff4e926a fix(shader): honor directed round32 in integer to f32 conversions
v_cvt_f32_i32 and v_cvt_f32_u32 used the host Convert which always
rounds to nearest even. When FLOAT_MODE bits 1:0 are directed, build
the f32 bits from the integer magnitude so discarded low bits follow
round toward +inf, -inf or zero, as measured on RDNA2 (gfx1036).

Co-Authored-By: Composer <noreply@cursor.com>
2026-10-10 16:34:07 -04:00
David ee0b249e4e fix(libkernel): report ENOTDIR from open with O_DIRECTORY on a file on Windows
(cherry picked from commit b2e9f59959f3eef10db3f68886ee9d9ec1d50ea4)
2026-10-10 20:31:35 +00:00
Hussein Kadhim 57da6e662e test(libc): check the exact unknown-error texts
(cherry picked from commit bbd7e79cda352794b86dea85b6db77ab08ad4cda)
2026-10-10 20:28:58 +00:00
Hussein Kadhim 5830d8e446 fix(libc): use FreeBSD errlst message texts for strerror and strerror_r
Twenty-five of the ninety-seven errno messages differed from FreeBSD releng/11.4 lib/libc/gen/errlst.c (for example errno 0, 30, 47, 62, 70 and 84).

(cherry picked from commit ce14c9ad7dc639335ff72b60122bae2bd0fee302)
2026-10-10 20:28:58 +00:00
Alex 951526662f fix(shader): honor directed f16 rounding in f16 conversions and ldexp
Directed FLOAT_MODE modes for v_cvt_f16_f32, v_cvt_f16_i16,
v_cvt_f16_u16 and v_ldexp_f16 were ignored, so results stayed
round-to-nearest-even. Hardware uses FLOAT_MODE bits 3:2 (round16);
the directed path runs only when f16 denormals are preserved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 16:27:01 -04:00
Dean 262c031692
Merge pull request #2907 from oneandonlydean/carry/libkernel-reserved-range-hint
fix(libkernel): map non-fixed hints inside a reserved range in place
2026-10-11 09:26:41 +13:00
Dean 3da4c3b665
Merge pull request #2653 from oneandonlydean/up2/descriptor-web-blocks
fix(recompiler): split descriptor webs whose Phis sit in different blocks
2026-10-11 09:26:31 +13:00
Hannah Lyons 6f1ef27953 feat(libSceAudioIn): export sceAudioInInit 2026-10-10 16:25:50 -04:00
Hannah Lyons 0c2d85238b feat(libkernel): implement preadv and pwritev 2026-10-10 16:21:56 -04:00
MarcZX100 5d7fc5a342 test(libc): keep macOS write watch stress bounded 2026-10-10 20:19:35 +00:00
Dean 56fb1b3b95
Merge pull request #2923 from MarcZX100/fix/hw-oracle-wave64-batch
fix(hw-oracle): batch wave64 probes into 512-row dispatches
2026-10-11 09:16:41 +13:00
Dean 7c83d020f9
Merge pull request #2937 from oneandonlydean/up3/vertex-barrier
fix(shader): drop s_barrier in vertex programs that share nothing between waves
2026-10-11 09:16:31 +13:00
Dean b8284f667f
Merge pull request #2936 from oneandonlydean/up3/emulated-compare-array-on-2d
fix(shader): give an emulated comparison of a 2D-array access a plain 2D mode
2026-10-11 09:16:22 +13:00
Dean b8a083b253
Merge pull request #2946 from SleglJan/fix/libSceSharePlay-null-heap
fix(libSceSharePlay): accept a null heap in sceSharePlayInitialize
2026-10-11 09:13:01 +13:00
Dean 7db7c9f908
Merge pull request #2919 from XairRrR/feat/libscevoice-mute-flag
feat(libSceVoice): track the port mute flag
2026-10-11 09:12:51 +13:00
Dean 94416bd6ad
Merge pull request #2764 from Get-fix/fix/audioout-ex-exports
fix(audio): export the sceAudioOutEx bitstream port functions
2026-10-11 09:12:41 +13:00
MarcZX100 a22206bfbd test(libkernel): fix Windows lstat fixture cleanup 2026-10-10 20:10:19 +00:00
MarcZX100 314c372285 test(libkernel): cover dangling Windows lstat links 2026-10-10 20:09:49 +00:00
MarcZX100 7f2a88262a fix(libkernel): detect Windows reparse points in lstat 2026-10-10 20:09:49 +00:00
Dean 6c008c180e
Merge pull request #2935 from AchrafReyani/feat/libkernel-siglongjmp
feat(libkernel): implement siglongjmp
2026-10-11 09:09:18 +13:00
Dean ea6661cce8
Merge pull request #2934 from AchrafReyani/feat/libc-nextafterf
feat(libc): implement nextafterf
2026-10-11 09:09:09 +13:00
Dean 230ce25b97
Merge pull request #2933 from AchrafReyani/feat/libc-llroundf
feat(libc): implement llroundf
2026-10-11 09:09:00 +13:00
goncalompontes 54c839959f feat(shader): decode GFX10 VOP3-encoded interpolation
v_interp_p1_f32_e64, v_interp_p2_f32_e64 and v_interp_mov_f32_e64
(VOP3Interp opcodes 0x200, 0x201 and 0x202) reach the decoder as VOP3
and were refused as unimplemented VOP3 opcodes. Decode them into the
existing VInterpP1F32, VInterpP2F32 and VInterpMovF32 opcodes with the
VOP3Interp operand layout, so the interpolation translation already
used by the VINTRP encodings handles them.

Encodings and operand layout follow LLVM's gfx10 MC tests for
VOP3Interp_Real_gfx10 (D69348). The interpolation parameter is the low
six bits of src0, the channel bits 6:7, the coordinate (or the
interpolation parameter of the mov form) is src1, and clamp and omod
reach the destination. op_sel, the packed-half selector, a third source
and abs/neg on operands that do not exist throw.
2026-10-10 21:07:55 +01:00
Chad 402bc1cdfc feat(agc): implement sceAgcBranchPatchSetThenTarget_0300 and SetElseTarget_0300 2026-10-10 15:05:43 -05:00
Dean a2cc109e64
Merge pull request #2931 from AchrafReyani/feat/libc-isinf
feat(libc): implement __isinf
2026-10-11 09:05:37 +13:00
Abdulrahman Elkordy a3437abd11 fix(agc): require 32-lane subgroups for wave32 mesh programs
The mesh stage was compiled at the driver's default subgroup width, while the translated mesh program lays wave64 lanes out on, and ballots over, a 32-lane host subgroup. Intel's Windows driver (Arrow Lake, 32.0.101.8991) reports subgroupSize 32 but prefers 16 for mesh shaders, and every agc_driver_mesh draw drew no triangle there. The mesh stage now gets VkPipelineShaderStageRequiredSubgroupSizeCreateInfo{32} when the program's hostSubgroupSize is 32 and the device lists the mesh stage in requiredSubgroupSizeStages, as compute pipelines already do.
2026-10-10 20:03:49 +00:00
Dean 43d2a7c4c0
Merge pull request #2911 from MarcZX100/codex/fix-libc-rename-win-errors-2403-latest
fix(libc): match FreeBSD rename errors on Windows
2026-10-11 09:02:14 +13:00
Dean 0ed05471e5
Merge pull request #2899 from MarcZX100/codex/mutexattr-prioceiling-2689
feat(libkernel): implement mutex priority ceiling attributes
2026-10-11 09:02:05 +13:00
Dean 97d347cf33
Merge pull request #2897 from LeandroLP23/feat/libkernel-pthread-sigmask
feat(libkernel): implement pthread_sigmask
2026-10-11 09:01:55 +13:00
Dean 1f6a7aa404
Merge pull request #2263 from jweidenh/fix/overlap-dependencies-without-colon
fix(tools): honor dependency declarations without a colon
2026-10-11 09:01:46 +13:00
Chad cbf86dfecf fix(agc): encode a one-dword NOP as the header-only form 2026-10-10 15:00:12 -05:00
Dean a8d24c7e44
Merge pull request #2910 from AchrafReyani/fix/unlink-readonly
fix(libkernel): unlink read-only files on Windows
2026-10-11 08:58:25 +13:00
Chad 7a3c38c005 fix(agc): name the group counts of a dispatch past the device limits 2026-10-10 14:58:18 -05:00
Chad 9cb2bf8de5 fix(agc): stop the dispatch look-ahead before indirect arguments an earlier dispatch may write 2026-10-10 14:58:18 -05:00
Dean 17d73d7fe7
Merge pull request #2896 from MarcZX100/fix/avplayer-autostart-race
fix(avplayer): keep title-started playback running
2026-10-11 08:58:15 +13:00
Chad 27e1ddca99 fix(recompiler): read SRT words through a null user-data pointer as zero 2026-10-10 14:51:20 -05:00
mugurc 92b20608e8 feat(relinker): convert for Rosetta with --to-rosetta
Rosetta runs AVX2, FMA, BMI1/2, F16C and MOVBE, but, unlike an Intel
host, it has neither RDSEED, CLWB nor RDPID. --to-rosetta converts
everything --to-intel does and lowers these three as well:

- RDSEED becomes RDRAND (the /6 form of the same opcode), which also
  returns a random value and sets CF.
- CLWB only writes a cache line back, so it becomes a NOP of the same
  length.
- RDPID becomes a load of 0 through an optional stub: Rosetta's TSC_AUX
  is a constant, not a processor index, so every thread reports
  processor 0. A site with no movable instruction after it for the jump
  is kept.

The flag implies --to-intel and conflicts with --windows. It is
independent of --macos: it only changes what the conversion produces, so
--macos alone leaves these instructions as they are, as on an Intel Mac,
and a title for Rosetta is relinked with --macos --to-rosetta. Intel
output is unchanged: the target is a parameter of the converter, Intel by
default.
2026-10-10 22:46:45 +03:00
Dean 9206c3e621
Merge pull request #2791 from alfalfa-star/perf/agc-storage-baseline-settled
perf(agc): take a storage image's generation baseline only when its guest bytes are settled
2026-10-11 08:45:14 +13:00
Alex 2f3f1a9c41 fix(shader): flush scalar f16 add/mul/sub denormals to signed zero
Scalar f16 add/mul/sub ignore FLOAT_MODE denorm16 flush bits on main.
Flush inputs when bit 0 is clear and results when bit 1 is clear at
nearest-even. Multiply checks tininess after 11-bit rounding
(0x387ff000); add/sub use 0x38800000.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 15:44:41 -04:00
Doston Abdullayev b1f0f1bff7 test(relinker): convert the non-ASCII working directory case in an ASCII directory
The relinker reads its arguments as narrow strings, so on a Windows
system whose ANSI code page cannot represent the directory it cannot
open the input, and the windows_working_directory case failed before
reaching the executable. Convert the case under an ASCII name and rename
the directory before starting the executable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Doston Abdullayev 28b1f1578f fix(relinker): walk Windows dependency diagnostics through the wide API
The --windows-diagnostics walker looked up modules and directories with
GetModuleHandleA, LoadLibraryExA, GetFileAttributesA,
GetModuleFileNameA and GetSystemDirectoryA, so under a directory outside
the ANSI code page it failed with "dependency diagnostics Windows API
failed" instead of naming the missing dependency.

Keep the walker's paths in UTF-8 and convert them at the Windows API
calls, which now use the wide functions. The entry stub passes it, and
prints, its paths as UTF-8 instead of the ANSI code page. The dependency
diagnostics test now builds its fixtures under a non-ASCII directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Doston Abdullayev 19803c0086 fix(relinker): start Windows executables from directories outside the ANSI code page
The Windows entry stub read its path with GetModuleFileNameA, which
turns every character the ANSI code page cannot represent into '?', and
then used it with SetCurrentDirectoryA and LoadLibraryExA. A converted
executable in such a directory (Japanese on a Western-locale system, an
emoji, a script without an ANSI code page) stopped at start-up with
ERROR_INVALID_NAME.

Read the path with GetModuleFileNameW and enter the directory and load
the libraries with SetCurrentDirectoryW and LoadLibraryExW, with library
paths stored as UTF-16. Messages and the --windows-diagnostics walker
still get the paths in the ANSI code page, as recorded in TechnicalDebt.

Fixes #2640

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Dean 8559ba7de1
Merge pull request #2758 from TheAggie/fix/libkernel-reserve-virtual-hint
fix(libkernel): place sceKernelReserveVirtualRange at its address hint
2026-10-11 08:41:52 +13:00
Dean cfa47a0f31
Merge pull request #2869 from MarcZX100/fix/agc-lto-layout-lifetime
fix(agc): keep pipeline layout alive during background LTO
2026-10-11 08:41:42 +13:00
MrMha 72f623197a fix(agc): keep polling unsatisfied memory waits after diagnostics
Keep WAIT_REG_MEM diagnostic timeouts from completing unsatisfied waits.
Register the existing gated-dispatch capture test with a 1ms diagnostic
timeout and document the missing-producer limitation.
2026-10-10 23:39:36 +04:00
MarcZX100 c0610950d7 fix(agc): ignore unchanged imported texture blocks 2026-10-10 19:37:13 +00:00
Sanjaysrinivas 982f7d7817 test(libkernel): cover cancellation recovery
Refs #1668. Complements #1141 with resource ownership and lifecycle regressions.
2026-10-10 21:27:49 +02:00
Get-fix fb380440d7 feat(libSceSystemService): select the console language with ANYPS5_LANGUAGE
sceSystemServiceParamGetInt always reported English (United States) as
the console language, so a title that follows the console's language,
such as Jelly5 (PPSA99505) with its Arabic text, can only show English.
ANYPS5_LANGUAGE now selects a console language number from 0 to 30
(21 is Arabic). Unset or empty keeps English (United States); any other
value throws at the language query instead of being ignored.

(cherry picked from commit 9bcf196daa01b07a22be876a7f1143149503e054)
2026-10-10 19:25:39 +00:00
MarcZX100 02941b8e3f fix(tools): detect non-void stub wrappers 2026-10-10 19:24:18 +00:00
JAB-dev bddcc71ea9 test(agc): require a repeated draw to reuse the cached draw
Submit the same vertex and pixel draw twice through the driver and
require the second one to hit the draw cache, with graphics pipeline
libraries and with APS5_NO_GPL=1. With pipeline libraries the pixel
stage is cached at its fixed push slot, so a lookup at the stacked
offset misses every draw on its layout. The driver exposes a copy of
its draw-cache counters for the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:24:11 +02:00
Hannah Lyons 8da88ad3ac feat(libSceAudioOut): export the sceAudioOutSys HDMI output functions 2026-10-10 15:23:02 -04:00
Hannah Lyons 5a43c9b0b9 feat(libkernel): implement pthread_rwlockattr_init and pthread_rwlockattr_destroy 2026-10-10 15:07:43 -04:00
Dean 4a747c4872
Merge pull request #2882 from MarcZX100/codex/relinker-nonascii-2692
fix(relinker): handle Unicode paths on Windows
2026-10-11 07:56:44 +13:00
Dean 3cb317fcfd
Merge pull request #2893 from LeandroLP23/docs/environ-technical-debt
docs(libkernel): record that environ is not libc's environment
2026-10-11 07:50:13 +13:00
Dean 29380369ad
Merge pull request #2890 from CnRJay/feat/audioout2-enable-chat
feat(audioout): declare sceAudioOut2EnableChat
2026-10-11 07:43:41 +13:00
Dean 1789305d7f
Merge pull request #2900 from JAB-dev/fix/agc-draw-cache-fixed-push-slot
fix(agc): look up cached draws at the fixed pixel push slot
2026-10-11 07:43:31 +13:00
QRMOE f153c28b52 docs(libc): record the fixed guest hostname policy
AI-assisted: yes. Record that gethostname exposes AnyPS5 rather than the native machine name. Console hostname configuration, sysctl integration and name resolution remain unverified and unimplemented. This one-line note is placed beside an unchanged libc compatibility entry so the branch merges cleanly into tested main 5edae3536.
2026-10-10 14:42:50 -04:00
QRMOE 3eb52310b6 fix(libc): keep the guest hostname independent of the host
AI-assisted: yes. Return AnyPS5 without reading the native machine name, hostname environment or network configuration. Preserve FreeBSD bounded-copy behavior, guest ENAMETOOLONG, null queries and success errno. The final tree passes a complete Windows Release build and guest_hostname/guest_errors repeated five times each on main 5edae3536. No new Linux or title test is claimed.
2026-10-10 14:42:43 -04:00
QRMOE 01072bfe97 test(libc): require a stable guest hostname
AI-assisted: yes. Verify AnyPS5 rather than the native PC hostname. Cover buffer capacities, guard bytes, maximum size_t capacity, null queries, success errno and thread-local isolation. The old implementation fails this regression; the final fixed tree passes the complete Windows build and five repeated runs each of guest_hostname and guest_errors on main 5edae3536. Linux and title tests of this new revision are pending.
2026-10-10 14:42:43 -04:00
QRMOE 8f32b6eca0 build(libc): avoid descriptor PR test registration overlap
AI-assisted: yes. Moves hostname test registration to avoid #2170 overlap. The full current-main build and focused Windows tests pass; implementation and test source are unchanged.
2026-10-10 14:42:43 -04:00
QRMOE 55075d1302 test(libc): cover hostname bounds and guest errno
AI-assisted: yes. Validates native hostname, every boundary capacity, buffer guards, truncation, null queries and thread-local errno.
2026-10-10 14:42:43 -04:00
QRMOE fb1b524415 build(libc): register guest hostname implementation and test
AI-assisted: yes. Builds the implementation and registers guest_hostname with a 20-second timeout.
2026-10-10 14:42:43 -04:00
QRMOE 2ed75efdcc feat(libc): implement guest gethostname
AI-assisted: yes. Implements the reported homebrew import with FreeBSD buffer behavior and the host hostname.
2026-10-10 14:42:43 -04:00
QRMOE 71ff6079cc test(libSceLibcInternal): regress successful utime errno changes
AI-assisted: yes. Add a deterministic backend that overwrites errno on success; verify restoration on success and retained failure errors. Extend native tests for current-time errno preservation. The new regression fails on original ca87abb and passes with this fix.
2026-10-10 14:42:36 -04:00
QRMOE da26c7e86e fix(libSceLibcInternal): preserve errno after successful utime
AI-assisted: yes. Restore guest errno only on successful utimes forwarding and retain delegated failure errors. Register the controlled-backend regression test. Windows library build and focused tests pass; Linux rerun pending.
2026-10-10 14:42:35 -04:00
QRMOE 858e9350aa test(libSceLibcInternal): verify guest utime with native timestamps
AI-assisted: yes. Checks independent native file times, null/current times, guest errno and rejected paths.
2026-10-10 14:42:35 -04:00
QRMOE 71040b6df5 feat(libSceLibcInternal): implement guest utime
AI-assisted: yes. Preserves the guest 64-bit time ABI and forwards through the existing utimes path. Registers guest_utime.
2026-10-10 14:42:35 -04:00
Dean 43e1425ba8
Merge pull request #2888 from CnRJay/feat/psml-mfsr-1300
feat(psml): declare scePsmlMfsrCreateContext1300 and scePsmlMfsrGetDispatchMfsrPacket1300
2026-10-11 07:40:19 +13:00
Chad 54b30588fd fix(recompiler): merge a loop selection whose arm leaves the iteration where its arms rejoin 2026-10-10 13:39:58 -05:00
Jan Šlégl 60148c0e96 fix(libSceSharePlay): accept a null heap in sceSharePlayInitialize
PPSA11386 calls sceSharePlayInitialize(NULL, 0x1800) at start-up and stops
on any non-zero result, so the console accepts a null heap. The library
keeps no state and does not use the heap; a zero size still throws, as its
error is unknown. libSceSharePlay gets its own CMakeLists for the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 20:38:56 +02:00
Dean Galvin 696b93a107 fix(shader): drop s_barrier in vertex programs that share nothing between waves
An NGG passthrough program on the vertex path whose s_barrier only orders wave 0's GS_ALLOC_REQ produced a workgroup OpControlBarrier, which the Vertex execution model does not allow; SPIR-V validation rejected the module at the program's first draw. In a Vertex-stage program the barrier now emits nothing when the program has no LDS or GDS access and no memory write or atomic, so no wave can observe another. With any of those it throws.
2026-10-11 07:32:30 +13:00
Dean Galvin 27353e16b7 fix(shader): give an emulated comparison of a 2D-array access a plain 2D mode
A comparison sample with a 2D-array address on a plain 2D color T# takes the emulated comparison, whose runtime modes were only the 2D-array and cube ones. No mode matched, and materialization threw that the image descriptor was incompatible with the static runtime image interface. The emulated comparison now also gets a 2D mode, as the native modes of a 2D-array access already have; the slice is ignored.
2026-10-11 07:32:16 +13:00
ThatsLeo 028b5c0e1f fix(agc): drain the device only when the swapchain is recreated
Resize drained the device before reading the surface extent, so a drawable
size that never matches the surface, as with fractional scaling, drained it
on every present.

(cherry picked from commit b4aae246766a108f78cd9ad29d7c874ea036d481)
2026-10-10 18:30:51 +00:00
Dean 1476f76941
Merge pull request #2878 from MarcZX100/fix/videoout-test-isolation-current
test(videoout): isolate application fixtures
2026-10-11 07:30:35 +13:00
Dean 268db5469a
Merge pull request #2818 from MarcZX100/codex/linux-test-pie-2803
fix(build): link Linux library tests as PIE
2026-10-11 07:30:25 +13:00
MarcZX100 70d4903158 fix(hw-oracle): batch wave64 probes into 512-row dispatches 2026-10-10 18:28:46 +00:00
Dean 7159f7f345
Merge pull request #2859 from babyhuey/feat/libkernel-cpuset-getaffinity
feat(libkernel): implement cpuset_getaffinity for the calling thread
2026-10-11 07:27:05 +13:00
Dean b78ced2b1e
Merge pull request #2858 from babyhuey/feat/libkernel-fstatfs
feat(libkernel): implement _fstatfs
2026-10-11 07:26:56 +13:00
Dean ce9ca660aa
Merge pull request #2857 from babyhuey/feat/libscehttp-recv-block-size
feat(libSceHttp): accept sceHttpSetRecvBlockSize
2026-10-11 07:26:46 +13:00
Achraf Reyani fc828e19e7 feat(libc): implement nextafterf
Export it next to remainderf, stepping to the adjacent float in the
direction of the second argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:25:24 +09:00
Achraf Reyani 3c43198943 feat(libc): implement llroundf
Export it next to lroundf and llround, rounding halfway cases away
from zero into the 64-bit guest long long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:25:23 +09:00
Achraf Reyani 909158503d feat(libc): implement atol and atoll
Both parse like strtol and strtoll in base 10. The guest long is 64
bits wide on every host, so atol uses strtoll rather than the host
atol, whose long is 32 bits on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:25:22 +09:00
Achraf Reyani e7311656c9 feat(libc): implement __isinf
Export the double version next to __isnan and __isfinite, returning
1 for either infinity like __isinff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:25:21 +09:00
MarcZX100 b0690903bb fix(libc): match FreeBSD rename errors on Windows 2026-10-10 18:25:17 +00:00
Achraf Reyani 0272f99ad3 feat(libkernel): implement siglongjmp
PokeMMO Prospero (PPSA98001) stops at siglongjmp (pebqbE5ws8s) from
libkernel. The title links its own FreeBSD sigsetjmp, so siglongjmp
follows FreeBSD's amd64 __siglongjmp and its sigjmp_buf layout: when the
save-mask flag at offset 88 is set it restores the mask saved at 72
through _sigprocmask, then reloads rbx, rsp, rbp, r12-r15 and the x87
control word and returns to the saved address with val, or 1 for 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:25:07 +09:00
MarcZX100 c96100aff1 fix(libc): map directory symlink loop errors
(cherry picked from commit d5e348c7b6846b2cd2cb5d1ecad9ad3493462047)
2026-10-10 18:24:36 +00:00
Dean df6b831400
Merge pull request #2831 from SleglJan/feat/libscenet-show-netstat
feat(libSceNet): declare sceNetShowNetstat
2026-10-11 07:23:26 +13:00
Dean 77641e25e0
Merge pull request #2812 from MarcZX100/codex/agc-pipeline-cache-vertex-limit-2804
fix(agc): size pipeline cache fixture to device limits
2026-10-11 07:23:15 +13:00
Joey Fisher f01f95d1f9 fix(agc): report a refused queue worker priority as a driver failure and reject unknown APS5_THREAD_PRIORITY values 2026-10-10 12:23:12 -06:00
Alex c3b8aa3264 fix(shader): flush f16 min3/max3/med3 denormal inputs
The ternary forms share minMaxF16 with v_min_f16 and v_max_f16 and follow
the same rule on gfx1036: a subnormal half input becomes a signed zero when
bit 0 of the f16 denormal field is clear, at IEEE=0 and IEEE=1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 14:21:31 -04:00
Dean 9c5d67fbe2
Merge pull request #2478 from itsbo5/feat/libkernel-dup
feat(libkernel): implement dup and dup2
2026-10-11 07:19:54 +13:00
Dean 2ece83f4dc
Merge pull request #2129 from sktharunbalaji13-cmd/contrib/scekernel-fdatasync
feat(libkernel): implement sceKernelFdatasync
2026-10-11 07:19:45 +13:00
Dean cf5d9bc1b5
Merge pull request #1772 from LuisBiceps/feat/libc-ifaddrs
feat(libc): implement getifaddrs and freeifaddrs
2026-10-11 07:19:36 +13:00
JAB-dev 5abc86f3d5 fix(agc): look up cached draws at the fixed pixel push slot
With graphics pipeline libraries a draw places the pixel shader's push
constants at the fixed fragment slot (Graphics::StagePushOffset) and the
draw cache records that offset, but lookupDraw still expected the stacked
offset after the vertex shader's push bytes. Every pixel stage then missed
as a layout mismatch, so no cached draw or draw recipe was reused and each
draw was captured and materialized again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 20:17:46 +02:00
Dean 9f87be5cc0
Merge pull request #2872 from CouchRiv/feat-libscecdlgg2p-dialog-close
feat(libs): provide the exports PPSA01285 imports that no library has
2026-10-11 07:16:15 +13:00
Dean bb29b62250
Merge pull request #2843 from MathiasDevelopes/feat/libsceajm-decode-split-resample-ex
feat(libSceAjm): implement sceAjmBatchJobDecodeSplit and sceAjmBatchJobSetResampleParametersEx
2026-10-11 07:16:06 +13:00
Dean 86d6cb5d8b
Merge pull request #2834 from MathiasDevelopes/fix/libkernel-stat-unconvertible-path
fix(libkernel): return ENOENT from sceKernelStat for unconvertible paths
2026-10-11 07:15:57 +13:00
Achraf Reyani f45d8933f2 fix(libkernel): unlink read-only files on Windows
FreeBSD's unlink ignores the file's own permission bits, so it succeeds
on a file the guest made read-only with chmod(0400). On Windows the guest
chmod sets the read-only attribute and _wunlink then failed with EACCES,
which sceKernelUnlink and unlink reported. When the path is a regular file
without write permission, make it writable before the single _wunlink and
restore the read-only attribute if the unlink fails, as remove() does
since #2342.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:15:42 +09:00
jweidenh 5fcac960e8 fix(tools): honor dependency declarations without a colon 2026-10-10 14:13:04 -04:00
Dean bf6e25a1dd
Merge pull request #2830 from SleglJan/feat/libscessl-ca-list
feat(libSceSsl): implement sceSslGetCaList, sceSslFreeCaList and sceSslUnloadCert
2026-10-11 07:12:36 +13:00
ps54all 08728f95b9 feat(libkernel): implement pthread_mutexattr_setprioceiling and getprioceiling
The mutex attribute now keeps its protocol and priority ceiling the way
FreeBSD's libthr does: the ceiling can be set and read only under
PTHREAD_PRIO_PROTECT (EINVAL otherwise), and setting a protocol resets it
to the highest SCHED_RR priority. Mutexes still do not apply priority
protection; that is listed as a silent stub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d10c024f8fdbcdfced0187550f272333264f07df)
2026-10-10 18:12:31 +00:00
Dean ec6383f9ab
Merge pull request #2824 from MarcZX100/codex/signal-sema-zero-count-2748
fix(libkernel): accept zero-count semaphore signals
2026-10-11 07:12:27 +13:00
Dean 077075d6c7
Merge pull request #2821 from MarcZX100/fix/relinker-windows-tls-reads-2761
fix(relinker): patch TLS reads after zero alignment padding
2026-10-11 07:12:19 +13:00
Chad 9cf85e94cb fix(recompiler): accept SDWA byte sources on v_cvt_f16_u16 and v_cvt_f16_i16
PPSA28416 stopped at v_cvt_f16_u16_sdwa dst_sel:WORD_0 dst_unused:UNUSED_PRESERVE src0_sel:BYTE_3. The integer source extraction already implements byte selects with src0_sext.
2026-10-10 13:11:10 -05:00
ps54all 3444ebf5cd fix(libkernel): map non-fixed hints inside a reserved range in place
A map without MAP_FIXED whose hint lies wholly inside a range still
reserved by sceKernelReserveVirtualRange is placed at the hint, as a fixed
map into the reservation would be. Hints outside reservations and ranges
that are partly mapped keep their hint behaviour. The reservation is
checked under the registry mutation, so it cannot be released and its
address reused between the check and the map (MarcZX100, #2687).

Fixes #2687

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2cY3SsTYnh4u4ZtEr2Adx
2026-10-11 07:10:29 +13:00
emirplus 6a7cce415a fix(savedata): recover from metadata setup failure 2026-10-10 21:09:00 +03:00
AlxcBTW a1827af12a fix(agc): treat other-shaped views of a depth surface's stencil plane as reused memory
Unity reuses the memory of transient render targets: in FPV Simulator
(PPSA10698) an RGBA8 1920x1080 color texture is sampled at the address
that a D32S8 surface's stencil plane occupied earlier. The lookup found
the stencil plane and threw "sampling the stencil plane ... is not
implemented", which ended the presentation.

9d65003c made depth-plane views in a format that cannot hold the plane
fall through to the ordinary texture path. A stencil-plane view whose
texels are not one byte wide cannot hold the 8-bit stencil plane
either, so it now falls through the same way.

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 20:03:09 +02:00
XairRrR 1232fd6cdf feat(agc-driver): prepare shader variants registration did not predict
Registration prepares the variants a shader's registered state
predicts; a draw or dispatch whose state needs another one threw
"prepared shader artifact is missing for the requested static ABI".
Titles that link their own libSceAgc build that state themselves and
never call the driver's static ABI resolution, so their draws differ
from the registered prediction. The missing artifact is now prepared at use, logged, and kept
with the snapshot like the deferred and null pixel cases. SourceHandleFor
now checks that the request refers to the registered code, as
InvocationFor already did.

Uncharted: Legacy of Thieves Collection (PPSA05684) still misses on
main 197ffac9 (after the fixed push slots of #2661) for its own pixel
shaders: "prepared shader artifact is missing for the requested static
ABI: address=85899411712 stage=5 wave=64 pushOffset=128
pushCapacity=128".
2026-10-10 19:59:24 +02:00
XairRrR e1dbb8fa17 fix(agc-driver): list both stages' interfaces when graphics interfaces disagree 2026-10-10 19:59:15 +02:00
XairRrR 4adca33251 fix(recompiler): describe the descriptor and modes when no runtime image mode matches 2026-10-10 19:59:15 +02:00
XairRrR 252955a185 fix(agc-driver): name the view and owner bounds when a guest buffer view exceeds its GPU owner 2026-10-10 19:59:15 +02:00
XairRrR c7cd20e82f feat(libSceVoice): track the port mute flag
sceVoiceSetMuteFlag was NotImplemented with an unknown signature and
sceVoiceGetMuteFlag was not exported. Signatures follow shadPS4's
voice.h: a port id and a bool, and for sceVoiceGetMuteFlag a port id
and a bool pointer. The flag is stored per port like the volume; an
unknown port throws and a null output pointer is an invalid argument.

Uncharted: Legacy of Thieves Collection (PPSA05684) imports
sceVoiceGetMuteFlag (Pc4z1QjForU), so on main it stops at startup with
"undefined symbol: Pc4z1QjForU".
2026-10-10 19:59:15 +02:00
XairRrR 048c9ff013 feat(agc-driver): render to COLOR_8_8 targets with SWAP_ALT
CB_COLOR_INFO COMP_SWAP 1 (SWAP_ALT) on a two-channel format stores the
x and w exports in its two channels (Mesa si_translate_colorswap,
"X__Y"). COLOR_8_8 UNORM and SNORM targets with it bind as R8G8 with
export mapping 0xec; blending into them still throws, since Vulkan
would apply alpha factors to the wrong channel.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped in its
first level with "unsupported color format 3 number type 0 component
swap 1".
2026-10-10 19:59:14 +02:00
XairRrR 70fe108712 fix(recompiler): fold extracts into a vector shuffle only between vectors
The specialization pass turned OpCompositeConstruct of extracts from one
composite into OpVectorShuffle without checking the types. When the
source is a struct (the {uint, uint} pairs of extended multiplies and
phis of them), the result is invalid SPIR-V ("The type of Vector 1 must
be a vector type"), which the NVIDIA driver (615.71.09) crashes on in
vkCreateGraphicsPipelines instead of rejecting. The fold now requires
both the source and the result to be vector types; a test builds the
struct and vector cases by hand.

Uncharted: Legacy of Thieves Collection (PPSA05684) crashed in the
driver's SPIR-V compiler right after loading its first level.
2026-10-10 19:59:14 +02:00
Yassine 9fc0af0b10 fix(avplayer): do not let auto start restart playback the title started
sceAvPlayerAddSource queues an auto start for a player created with auto
start or without an event callback. When the title enabled its streams
and called sceAvPlayerStart before the controller thread ran it, the auto
start called Start again on the playing player, which stopped it, released
every video buffer, including the frame the title held, and started the
film over. guest_avplayer occasionally caught this as "video frame is not
a texture allocation"; right after the test's own start, 8 texture
buffers were released in 15 of 15 runs.

The auto start now starts the player only while it is still ready, and
checks that under the player lock together with the start.

TestAutoStartKeepsStartedPlayback starts a callback-less player itself and
checks that no texture buffer is released afterwards and that the frame
it holds stays allocated. It fails on every run without the fix.
2026-10-10 17:56:25 +00:00
LeandroLP23 68a1aea611 docs(libkernel): record that environ is not libc's environment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:48:06 +02:00
LeandroLP23 df415ff1fd feat(libkernel): implement pthread_sigmask
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:45:28 +02:00
Chad a73b4e3f6d feat(audioout): declare sceAudioOut2EnableChat
Imported by party-ps5-shipping.prx bundled with PPSA28416.
2026-10-10 12:43:28 -05:00
Chad beba4ce204 feat(psml): declare scePsmlMfsrCreateContext1300 and scePsmlMfsrGetDispatchMfsrPacket1300
PPSA28416 imports both from libScePsml; the names hash to NIDs kLF7WtQ1-Dg and DDVUyPyYHTA.
2026-10-10 12:42:01 -05:00
ctj01 b7d5f18c41 fix(relinker): drop the input PT_PHDR and PT_INTERP from Linux output
The Linux patcher writes its own PT_PHDR and PT_INTERP but also copied
the input's. glibc takes the load bias from the last PT_PHDR, which was
the input's entry with the pre-relink address, so such an executable
crashed at start. Both copies also took program header slots, so an
input with PT_PHDR and PT_INTERP and no spare slots failed to relink.
2026-10-10 17:33:59 +00:00
MarcZX100 c5ffebe15a fix(relinker): preserve empty Windows arguments 2026-10-10 17:28:07 +00:00
MarcZX100 fe81332b08 test(relinker): cover unicode guest module paths 2026-10-10 17:22:07 +00:00
MarcZX100 8cbebea6b7 fix(relinker): preserve unicode module paths 2026-10-10 17:22:07 +00:00
aplatogg b74774f713 fix(relinker): support non-ASCII input paths on Windows
The MinGW CRT delivers argv to main as ANSI code page bytes, and every narrow string became a filesystem path through the same code page, so a game in a directory with characters outside the code page failed to open (#2692). Read the command line as Unicode (wmain via -municode), keep paths as UTF-8 strings, convert at the filesystem boundaries through Io::NativePath and Io::Utf8Path, and run the --autorun output through CreateProcessW.

(cherry picked from commit 30a5181f8a71b177cf2dc03334e39998938b3472)
2026-10-10 17:22:07 +00:00
arcwiser e5a81a3ca9 test(videoout): isolate application fixtures
(cherry picked from commit 7e982a521f2ba5fafabcba45c78cb23918fa9007)
2026-10-10 17:10:51 +00:00
Alex 1ab577f817 fix(shader): follow IEEE_MODE in v_div_fmas_f32 NaN selection
v_div_fmas_f32 always quieted source NaNs and let a NaN addend
hide the default NaN from an invalid product. Reuse the existing
bit selection helpers, measured on gfx1036 in four float modes.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
2026-10-10 13:08:02 -04:00
Renan Pires 9a3e55b8e8 feat(libkernel): implement _fstatfs 2026-10-10 13:07:42 -04:00
Alex 2d0cf26804 fix(shader): flush f16 min/max denormal inputs
RDNA2 min/max flush half inputs to signed zero when input
preservation is disabled, while output flushing alone keeps them.
Apply this to the measured binary forms and pin the hardware rows.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
2026-10-10 13:07:31 -04:00
Abdulrahman Elkordy 510787170e fix(agc): link optimized pipelines with the library store's layout
The background link-time-optimized link used the Pipeline's own layout, which ~Pipeline destroys right after marking the slot released, and ClearCachedPipelines destroys the cached pipelines before ClearPipelineLibraries waits for pending links. A link already past the released check then created its pipeline with a destroyed VkPipelineLayout. On Intel's Windows driver (Arrow Lake iGPU, 32.0.101.8991) agc_driver_vertex_fetch, agc_driver_pixel_interlock and agc_driver_mesh faulted inside igc-default64.dll every run, and agc_driver_prepared_exports and agc_driver_pixel_barycentric_emulation intermittently; all passed with APS5_NO_PIPELINE_LTO=1. The library store's layout, made from the same create info and used for the libraries, lives until ClearPipelineLibraries has waited for the pending links.

(cherry picked from commit 758eeb9fb255d88c41945b299dc3ec5ac1578331)
2026-10-10 16:58:17 +00:00
Alex 2a675598f2 feat(libSceNpManager): add the missing request timeout export
Validate timeout arguments and track live requests so unknown or deleted
ids return REQUEST_NOT_FOUND. This supplies the remaining absent load
import alongside the dialog Close export; timeouts follow the existing
offline network model and are not stored.

Co-Authored-By: GPT-6.1-sol <noreply@openai.com>
2026-10-10 12:57:01 -04:00
Hannah Lyons 5ac10820ea feat(libScePosixForWebKit): implement arc4random_buf 2026-10-10 12:49:31 -04:00
Alex 18590d1f79 feat(libs): provide the missing G2P dialog Close export
Eager binding fails when a caller imports sceG2PDialogClose.
Add the missing throwing stub alongside the existing G2P exports
and record the assumed Close signature in TechnicalDebt.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
2026-10-10 12:40:57 -04:00
Hannah Lyons d2c160be76 feat(libkernel): implement cpuset_getaffinity for the calling thread 2026-10-10 12:40:56 -04:00
Hannah Lyons e203c43221 feat(libSceHttp): accept sceHttpSetRecvBlockSize 2026-10-10 12:40:55 -04:00
MathiasDevelopes e8209307e9 feat(libSceAjm): implement sceAjmBatchJobDecodeSplit and sceAjmBatchJobSetResampleParametersEx
sceAjmBatchJobDecodeSplit queues a split run job with the stream
sideband, as sceAjmBatchJobDecode does for a single buffer pair.
sceAjmBatchJobSetResampleParametersEx with a zero ratio change per
sample sets the ratio as sceAjmBatchJobSetResampleParameters does; a
non-zero change throws, since its ramp is unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:24:54 +02:00
Alex d59efa478e test(shader): pin mixed-source tininess after rounding
Measure the mixed f16/f32 boundary on gfx1036 and pin both factor
slots, half selection, signs and zero f16 addends in the existing test.
Record this measured scope while keeping legacy mad/mac unchanged.

Co-Authored-By: Codex gpt-6.1-sol <noreply@openai.com>
2026-10-10 12:24:36 -04:00
Alex a68dbbe112 fix(shader): detect f32 tininess after rounding when flushing products
With f32 denormals flushed, RDNA2 flushes a product only when its value
rounded to 24 bits in the current round mode is below 2^-126. The
tiny-product check tested the exact product, so products that round up
to 2^-126 became zero in v_mul_f32, v_mul_legacy_f32, v_mullit_f32 and
zero-addend f32 FMAs. The separately rounded v_mad_legacy_f32 and
v_mac_legacy_f32 keep the exact check, as they are not measured there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 12:24:36 -04:00
Lexroid ef5221a1e6 fix(recompiler): accept byte source selects on v_cvt_f16_u16 SDWA
v_cvt_f16_u16 SDWA only accepted word and dword source selects. Silent
Hill Townfall (PPSA33286) converts the top byte into the low half of a register
and keeps the high half (src0_sel:BYTE_3 dst_sel:WORD_0
dst_unused:UNUSED_PRESERVE), so its shaders failed to recompile. The
generic SDWA source path already zero-extends byte selects, which is the
u16 value the conversion expects, so the rule now accepts every source
select, with whole and partial destinations.

agc_driver_sdwa_cvt_f16_u16 runs four byte selects with dword, WORD_0
and WORD_1 destinations on the GPU and checks the converted halves and
the preserved bits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d55dfe8b33c6ee418f40a92e49236f8679a6470b)
2026-10-10 16:17:56 +00:00
MathiasDevelopes 7fe298bfab fix(libkernel): return ENOENT from sceKernelStat for unconvertible paths
A guest path whose bytes the host cannot convert to a native path made
ResolvePath throw std::filesystem::filesystem_error, which aborted the
process. No file can have such a name on the host, so stat reports
ENOENT, as for any other missing file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:15:59 +02:00
Get-fix d686f7057c fix(libkernel): export execvp
VLC (PPSA85300) imports execvp (0NJDcQ2B8vE) from libkernel and fails
to load because no library exports it. Replacing the process image is
not supported, so it throws if called, like sceSystemServiceLoadExec
does for executable replacement. VLC itself cannot reach the call: its
fork and vfork fail with ENOSYS, so the child that would call execvp is
never created.
2026-10-10 19:12:49 +03:00
Lexroid 45a561aea5 fix(libkernel): accept a zero count in sceKernelSignalSema
sceKernelSignalSema threw invalid_argument for a count of 0. Marvel's
Wolverine (PPSA03671) signals with a count computed as min(a, b) - c,
which can be 0, and ignores the result, so the throw ended the title a
few minutes in. A zero count now adds no tokens and returns SCE_OK, as
in shadPS4 and Kyty. A null semaphore and a negative count still throw.

guest_kernel_errors signals 0 on a full and on an empty semaphore and
checks that the count is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7191d34c4d79622ba71087f0da2b75eb81ad2c23)
2026-10-10 16:12:43 +00:00
AlxcBTW fccfbee72b fix(relinker): convert Windows guest TLS reads after zero alignment padding
The Windows TLS rewriter only patches FS-relative instructions that
CodeInstructionCollector decodes. Code that no symbol, unwind range or
root reaches is covered by a linear sweep that starts after int3 padding
and stops at the first instruction beginning with two zero bytes, so
zero-filled bytes are not read as code.

The .NET NativeAOT homebrew titles pad between functions with zero bytes
instead of int3 and have unwind entries for only part of their code. In
Prospero Vibrate (PPSA99920) the sweep ended at the padding after the
first function. Functions reached only through switch jump tables, which
the control-flow graph does not follow, or through pointers it cannot
resolve kept 105 of 670 FS loads unpatched: 84 `mov reg, fs:[0x28]`
stack-guard reads (65 into rax, 19 into rcx) and 21 `mov rax, fs:[0]`
thread-pointer reads. The title faulted reading address 0x28 within a
second of start.

The sweep now treats a zero run that follows a jump, call, return or
trap and ends at the next 16-byte boundary as alignment padding, and
continues at that boundary. A call counts because a function can end in
a call to a noreturn function. Zero fill after straight-line code, or a
whole zero 16-byte block, still ends the sweep as before.

All 670 FS loads in PPSA99920 are now patched, as are the 102 of 685 in
Prospero Explorer (PPSA99109) and the 103 of 718 in Prospero Multi Tools
(PPSA99110). New tls_function_coverage padding cases: loads behind zero
padding after a return, a call and a jump, with 13, 2, 1 and 5 zero
bytes, are patched; a load behind zero fill after a nop is left
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0306c677784b6c4272990ce65f6daf9fb2dbc3ca)
2026-10-10 16:08:54 +00:00
MarcZX100 046680da48 fix(libkernel): reject empty mkdir paths 2026-10-10 16:06:21 +00:00
MarcZX100 734fe53f82 test(libkernel): cover mkdir at guest root 2026-10-10 16:06:21 +00:00
MarcZX100 5837210c9f fix(libkernel): preserve mkdir error handling for trailing paths 2026-10-10 16:06:21 +00:00
Achraf Reyani 3779ffa375 fix(libkernel): accept a trailing slash in sceKernelMkdir
sceKernelMkdir checked that the parent of the resolved path exists, but
for "dir/" std::filesystem::path reports "dir" itself as the parent, so
the call failed with ENOENT and created nothing, while FreeBSD's mkdir
(and the POSIX mkdir export) accept it. Strip trailing separators first,
and report ENOTDIR when the parent exists but is not a directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5f74ddba8b346e6c552cf02554d47382708206f3)
2026-10-10 16:06:21 +00:00
ThatsLeo c2a159bab7 fix(build): link the Linux library tests as PIE
The Linux loader takes the unnamed main image for guest code, as the
relinker's ET_DYN output is. Fedora's GCC does not default to PIE, so the
test executables were ET_EXEC and three loader tests failed.
2026-10-10 16:02:27 +00:00
Karan Vora 4779bf6174 Merge remote-tracking branch 'origin/main' into perf/shader-dot2-f32-fast-path
# Conflicts:
#	core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
2026-10-10 12:02:12 -04:00
Karan Vora b59e084b3a Merge remote-tracking branch 'origin/main' into perf/shader-pkrtz-native-rte
# Conflicts:
#	core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
#	core/shader/recompiler/SpirvBackend/src/SpirvAlu/SpirvAluEmitterMath.cpp
2026-10-10 12:01:47 -04:00
Jan Šlégl 875ff3f8d9 feat(libSceNet): declare sceNetShowNetstat
PPSA11386 imports it; on main it is one of the title's three missing
imports, with sceSslGetCaList and sceSslFreeCaList, and the title does not
call it during its start-up. The signature is unknown, so it is declared
without parameters and throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:01:23 +02:00
Jan Šlégl 33184a1b33 feat(libSceSsl): implement sceSslGetCaList, sceSslFreeCaList and sceSslUnloadCert
PPSA11386 imports sceSslGetCaList and sceSslFreeCaList and PPSA15508
imports sceSslUnloadCert; on main all three are missing and the loaders of
both titles stop on them. No root certificate bundle is shipped and no
loaded certificate is kept, so an SSL context holds no certificates:
sceSslGetCaList clears the list and returns NOT_FOUND, as sceSslGetCaCerts
does; sceSslFreeCaList accepts only that cleared list; sceSslUnloadCert has
nothing to drop and is assumed to return 0. A null list returns the
invalid-argument code that sceSslGetCaCerts and KytyPS5 return. An unknown
context and a list sceSslGetCaList did not return throw, as their codes are
not confirmed. Signatures and the SceSslCaList layout follow SharpProspero
and shadPS4.

guest_ssl_tests now links libc, as guest_http2_tests does, so an exception
thrown from libSceSsl unwinds with the same unwinder that resumes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:01:23 +02:00
Karan Vora b6442c2137 Merge remote-tracking branch 'origin/main' into perf/shader-pack-conversions-f32 2026-10-10 12:01:10 -04:00
Karan Vora bce20b2f35 Merge remote-tracking branch 'origin/main' into perf/shader-compare-constant-flush 2026-10-10 12:01:08 -04:00
Karan Vora 14867c51a3 Merge remote-tracking branch 'origin/main' into perf/shader-float-to-int-once 2026-10-10 12:01:07 -04:00
Jan Šlégl 7eba9f5b16 perf(recompiler): index memory users once per indirect image planning pass
MemoryIndexBelongsTo walked every instruction of the program and asked
BufferAccessOf, AddressOpcodeInfoOf and ImageOpcodeInfoOf about each one.
TryMakeTableImage calls it for each of a table handle's eight descriptor
dwords and once more for a material key, and PlanIndirectImages calls
TryMakeTableImage for every image instruction whose handle is not planned
yet, so each such instruction could cost up to nine walks of the whole
program. PlanIndirectImages now indexes the instructions that access
memory by their memory index once, before it plans, and
MemoryIndexBelongsTo looks the index up while that pass runs. The
planning pass adds, removes and changes no instruction, so the index
stays valid until the pass drops it at its end. Outside the pass, where
the function has no caller, it walks the program as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-10 17:50:00 +02:00
ThatsLeo 5d4e0f2b43 fix(agc): size the pipeline cache fixture to the device's vertex input limits
Mesa ANV reports 29 vertex attributes; Vulkan guarantees 16.
2026-10-10 15:41:32 +00:00
boykopovar 57f96fd2b3
Merge pull request #2808 from boykopovar/ci/pr-intake-min-10
ci(pr): set min intake pr count to 10
2026-10-10 18:40:02 +03:00
boykopovar f4b6e1011d ci(pr): set min intake pr count to 10 2026-10-10 18:37:56 +03:00
Dean ca349535f5
Merge pull request #2681 from oneandonlydean/up2/swept-buffer-staging
perf(agc): stage read and written buffer elements a dispatch sweeps
2026-10-11 04:36:15 +13:00
Karan Vora c3742a3995 Merge remote-tracking branch 'origin/main' into perf/shader-coherent-alias
# Conflicts:
#	core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ProgramMetadata.hpp
2026-10-10 11:34:02 -04:00
Karan Vora 5a16ed15b1 docs(shader): list plain buffer loads beside GLC accesses as not coherent 2026-10-10 11:33:29 -04:00
krishnaraya 1feb89cd56 fix(agc): read X for a DST_SEL W of 5_6_5 textures as measured on gfx1035
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 11:22:07 -04:00
krishnaraya 22cb7094ae fix(agc): sample 5_6_5, 1_5_5_5 and 4_4_4_4 textures in AMD's channel order
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 11:15:42 -04:00
Tharun Balaji 57be03a4c1 fix: guard sceKernelFdatasync against guest socket descriptors
Add the guest socket descriptor guard to sceKernelFdatasync before any
native syscall, matching the existing sceKernelFchmod pattern. This
prevents high guest socket descriptors (e.g. 0x10000000) from reaching
the Windows CRT _commit, which would trigger the invalid-parameter
handler, and ensures the correct SCE error is returned on all platforms.

Refactor fdatasync_nid_postfix to delegate to sceKernelFdatasync via
PosixResult, removing the duplicated socket guard and native syscall.

Extend GuestFilesystem tests to cover:
- sceKernelFdatasync on a valid guest socket returns SCE EINVAL (0x80020016)
- sceKernelFdatasync on a closed guest socket returns SCE EBADF (0x80020009)
- sceKernelFdatasync on a high invalid descriptor (0x7fffffff) returns SCE EBADF
- closed-ordinary-descriptor tests now run on Windows (verified _commit on
  a closed descriptor returns EBADF without provoking the CRT handler)
2026-10-10 20:42:36 +05:30
alfalfa-star 127e028825 perf(agc): list a dispatch or draw as a copied writer only while it has a CPU write-back
A recorded dispatch or draw whose use needs completion work goes into the
copied-writer lists (VulkanDevice's copiedWriters, DrawCopiedWriters).
Fills, buffer copies and indirect argument reads treat every write of a
listed object as a store the CPU makes when its batch is reaped, and wait
for that batch. Completion work is also needed for the BDA fault check
alone, and the written sub-ranges of GPU copies are copied back by the
GPU (RecordCopyBacks) before the listing. Such an object has no CPU
write-back (HasCopiedWrites is false), and its stores are ordered by the
barriers like direct writes, yet it was listed and waited for.

Both lists now take an object only when HasCopiedWrites holds after
MarkGpuWrites. The completion action still runs for the fault check.

agc_driver_copied_writer_copy records a dispatch that reads through
global (BDA) loads and stores through a bound buffer into registered
memory, then copies that output on the GPU (VulkanDevice::CopyBuffer)
before the batch ran. It checks that the copy is a transfer between the
host imports without a sync, and the copied bytes. Without the change the
copy waits for the dispatch's batch.

PPSA14632 (LEGO Horizon Adventures): every one of the DMA_DATA copy
waits counted over 75 s came from such writers. Queue 0's GPU-mutex hold
for copies drops from 3.5 s to 30 ms per 10 s, and presents rise from
about 102 to 109 per 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:10:57 +02:00
alfalfa-star 75b540c216 perf(agc): take a storage image's generation baseline only when its guest bytes are settled
An upload of a storage image up to 1 MiB reads the surface's guest bytes
into a baseline (#1599), which a later write-back compares against for
blocks the CPU stamped. When a unit shadow, another image's pending
results or a recorded GPU store covers the surface, that read goes
through the flush hook: the shadow is published and the worker waits for
the GPU, although the upload itself runs on the GPU from the import.

The baseline is now taken only when nothing of that kind overlaps the
surface. Otherwise the image has none, and its write-back keeps the CPU's
bytes for stamped blocks, the rule before #1599. TechnicalDebt's entry
names the condition.

agc_storage_baseline_settled creates a storage image over a watched host
import with a recorded store pending over part of it and checks that the
upload did not submit the open batch; without the change the baseline
read syncs on that store. agc_unchanged_cpu_stamps (#1599) still passes.

PPSA14632 (LEGO Horizon Adventures) refreshes such images about 870
times per 10 s from queue 0 dispatches: the hook's recorded-store syncs
go from about 3400 waiting 4.0 s to about 630 waiting 0.3 s per 10 s,
and a direct dispatch's device call from 356 to 107 us.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:07:47 +02:00
Dean de5e541d8f
Merge pull request #2673 from oneandonlydean/up2/image-dedupe
perf(agc): resolve a sampled element repeating the one before it to the same texture
2026-10-11 04:07:26 +13:00
Dean eb94c554da
Merge pull request #2672 from oneandonlydean/up2/image-memo
perf(agc): memoize decoded image descriptors and their texture cache entries
2026-10-11 04:07:17 +13:00
tototomate123 ded8b4df23 fix(relinker): preserve executable exports and dynamic lookup tags 2026-10-10 16:58:39 +02:00
tototomate123 0a229a43dc fix(shader): evaluate signed minimum in runtime SRT expressions 2026-10-10 16:57:32 +02:00
tototomate123 9107be460f fix(libkernel): implement kernel futimes with POSIX error translation 2026-10-10 16:57:31 +02:00
tototomate123 7ea423f78b fix(relinker): map executable section addresses through load segments 2026-10-10 16:57:31 +02:00
tototomate123 a79bf5a727 fix(libkernel): return guest errors from chmod calls 2026-10-10 16:57:31 +02:00
Dean Galvin 63fb5779b3 perf(agc): resolve a sampled element repeating the one before it to the same texture
A build's sampled image elements often repeat the element just before them
in plan order (the same eight descriptor words). Each still took its own
stage-A record (decode, collect, DCC key read, cache entry) and its own
stage-B lookup.

The lookups run in plan order and nothing runs between two consecutive ones,
so a repeated element's lookup would find the state the previous lookup just
left: the entry it validated or made, current against the same collect. Such
an element now binds the previous element's texture (when the depth-compare
flag matches too, which is part of the cache key), and stage A gives it a
record of the decoded descriptor only. An element repeating an earlier but
not the immediately preceding one still takes its own lookup, as does any
element after a storage image lookup.
2026-10-11 03:35:08 +13:00
Dean Galvin 0209c64245 perf(agc): memoize decoded image descriptors and their texture cache entries
A resource build decodes every image element's eight descriptor words,
describes the surface (a mip layout with a vector of levels) and finds the
sampled texture's cache entry by hashing its key, once in stage A and again
in stage B. Most elements repeat a small set of descriptors from build to
build.

Each worker now keeps a small direct-mapped memo by descriptor words of the
decoded resource, its guest size and view component mapping (pure functions
of the words) and of the cache entry the words last found. The entry is
reused only while the sampled texture cache has erased no entry since it
was found (an erase counter bumped by eraseTexture), so the list iterator is
still valid and still holds the same key; anything else takes the hash
lookup.
2026-10-11 03:35:08 +13:00
TideOPL aa9ee1b0ad fix(agc): give pooled buffers a VkBuffer of exactly the requested size
Buffer and DeviceBuffer created their VkBuffer at the pool's size class, so
a robust read past the requested size stayed in bounds and returned the
bytes an earlier user of the pooled memory left there instead of an
out-of-range result. Each VkBuffer now has the requested size, created with
the pool's usage, over memory of its class (or its slab slot); one taken
from the pool for a different size is recreated over the same memory at
the same offset. agc_buffer_pool follows a pooled buffer by its memory, so
its class and reuse cases hold with the exact-size buffers.
2026-10-10 15:25:21 +01:00
Dean 5edae35361
Merge pull request #2657 from oneandonlydean/up2/address-draw-key
perf(agc): skip the resource-cache key and lookup for address-based draws
2026-10-11 03:15:31 +13:00
Celegans12 48693920aa perf(recompiler): reuse dominance intersection storage
Intersect copied fixed-point sets without allocating each intermediate.
Preserve sorted results and the existing analysis iteration order.
Compact oversized storage only when publishing a changed set.
Keep an allocating control switch outside the cache key.
Compare complete fixed points over empty intersections, loops and DAGs.
Register the same equivalence fixtures for the allocating control.
2026-10-10 16:08:00 +02:00
alfalfa-star 14c2eca3b0 perf(agc): sync only the source for DMA_DATA copies into host-only memory
A DMA_DATA copy larger than the store limit runs as a transfer between
host imports. When the destination is not registered guest memory (the
GPU can neither read nor write it, so no import exists), the transfer
was refused and the packet drained the device: every batch recorded so
far was submitted and waited for, then the CPU copied.

Such a copy only has to see the source's results. When CopyBuffer
refused for want of an import (path 2) and nothing can still store over
the destination (VulkanDevice::StoresPendingOver: a recorded write, a
label, a copied write-back, a storage image's pending write-back or a
unit shadow), the packet now flushes storage results pending over the
source and waits for the batches that write it (Recorder::SyncThrough),
then copies on the CPU without a drain. Anything else still drains as
before. The [sync] line counts these copies.

agc_driver_tests copies a buffer the GPU just wrote into host memory,
once directly and once behind a label into the destination, and checks
the bytes and that the copy did not drain.

PPSA14632 (LEGO Horizon Adventures) copies 256 KiB of GPU results into
host memory this way, about 50 times per 10 s: device drains drop from
about 50 to none per 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:07:13 +02:00
Dean db343a934c
Merge pull request #2656 from oneandonlydean/up2/buffer-slabs
perf(agc): sub-allocate small host buffers from shared memory blocks
2026-10-11 02:59:36 +13:00
Yuvaraj b7dec57a84 test(avplayer): stop the unsynced test racing the player's auto-start
TestUnsyncedVideoKeepsUpWithAudio built its player without an event
callback, which enables auto-start (autoStartEnabled = init.auto_start ||
callback.event_callback == nullptr). The controller thread then enables the
streams and starts playback shortly after the source is added, racing the
test's own sceAvPlayerEnableStream. When the controller won,
Source::EnableStream saw started == true and the test failed with "enable
video failed".

The test now passes an Events object, as the other tests that drive the
player by hand do.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 19:25:28 +05:30
Dean 8b812318b4
Merge pull request #2683 from oneandonlydean/up2/refresh-proof
perf(agc): keep a storage image's refresh proof while nothing it read moved
2026-10-11 02:37:50 +13:00
Dean 808d8dc43a
Merge pull request #2691 from oneandonlydean/up2/parallel-snapshot-compare
perf(agc): compare large stale draw snapshots on helper threads
2026-10-11 02:35:16 +13:00
Dean 9526f0d739
Merge pull request #2685 from oneandonlydean/up2/stale-snapshot-patch
perf(agc): patch a stale storage snapshot's changed blocks in place
2026-10-11 02:34:59 +13:00
Dean e668748ce2
Merge pull request #2664 from oneandonlydean/up2/stale-snapshot-reuse
perf(agc): reuse a stale storage snapshot whose bytes are unchanged
2026-10-11 02:34:43 +13:00
boykopovar ba2a0a31ff
Merge pull request #2750 from rohankmr414/fix/videoout-output-status-with-vrr
fix(videoout): add throwing GetOutputStatusWithVrr export
2026-10-10 16:13:38 +03:00
Get-fix f2b4bf3b5b fix(audio): export the sceAudioOutEx bitstream port functions
Jelly5 (PPSA99505) imports sceAudioOutExGetMonitorInfo (PhnNN0UEV6Y),
sceAudioOutExConfigureOutput (VcE+gXSwFXI), sceAudioOutExOpen
(6X6dp+07h4U) and sceAudioOutExClose (0TfjSulCV2A) from libSceAudioOut
and fails to load because no library exports them. It calls them only
for its optional HDMI bitstream output, and their signatures are
unconfirmed, so they are exported without an implementation and throw
if they are called, like sceSaveDataCancel.
2026-10-10 16:12:11 +03:00
boykopovar 78aedb40e2
Merge pull request #2708 from boykopovar/feat/strict-sce-module-search
feat(relinker): strict sce module search
2026-10-10 16:01:29 +03:00
Scott Schuster 58e871cf2a fix(libkernel): place sceKernelReserveVirtualRange at its address hint
Without MAP_FIXED the address is a hint, as for FreeBSD's mmap: the reservation goes at the hint when that range is free, else at the first free range above it. The hint was dropped, so every hinted reservation landed at the lowest free address.

RetroArch (PPSA99169) reserves its cores' direct-memory heap near 0x2000000000 outside the GPU window (0x200000000-0x300000000) and refuses a range inside it; with every reservation at 0x200400000 the heap was never made, and Dolphin's first aligned allocation returned null.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:59:00 -05:00
Dean Galvin e8b43459a6 perf(agc): keep a storage image's refresh proof while nothing it read moved
Every draw into a resident target refreshes the target's storage image
(StorageTexture::Refresh): a pending-registry scan for an alias,
FlushPending over the surface, the collect, the key proof, a
whole-surface UnchangedSince, four vectors and a generation update over
every 64 KiB unit, nearly always finding the image current.

A refresh that finds the image current now keeps a proof: the image's
generation and uploaded keys, its key proof's generation and the pending
registry serial. The next refresh is answered from it when the image's
own state is still that, the surface and its key range are unstamped
since those generations (CollectWrites over both, then one
UnchangedSinceAll), and no other image has results pending over the
surface: the registry serial is unchanged, or the registry is scanned and
holds none (a newly pending image, a flush in progress). The proof is
taken only under GuestMemory::GpuMutex, without a pending alias, with
stable keys and when no other pending image overlaps the surface; any
full refresh drops it. A CPU write, a driver or GPU store, a key store,
another image's pending results or a different image therefore always
refresh in full, and the image's own pending results (a draw into it)
keep the proof.

agc_driver_recorder_tests refreshProofTests: an unchanged image and one
holding its own pending results are proved; a CPU write, a driver store
into the surface, a key store, another image's pending results, a new
image of the surface and a fast clear of the keys each refresh in full.
2026-10-11 01:57:32 +13:00
Scott Schuster 8c06af0ad9 fix(agc): honour primitive restart in mesh-path triangle strips
A geometry (NGG) strip draw on the mesh path assigned every primitive the next index positions without looking for the restart index: a triangle spanning a restart fetched vertex 0xFFFF and was drawn to wherever that read landed, and the strip parity never reset, so after an odd-length strip every triangle's winding flipped and face culling dropped it.

For an indexed strip draw with restart enabled and the restart index present, the draw now records each position's strip start (one past the last restart at or before it) and passes the table after the mesh arguments, flagged in draw word 3. The mesh prologue reads the start of its primitive's last vertex: a primitive whose start lies past its first vertex spans a restart and is made degenerate, and the others take their parity from their strip's start (or the draw's first index). The restart vertex itself fetches vertex 0. The table is built from the index bytes the draw already reads (its copy, or the guest memory an in-place import reads), next to #1968's restart-aware highest-index scan.

The new Mesh.cpp test draws quads as four-index strips each followed by a restart (16- and 32-bit indices, and an indirect draw starting mid-buffer) with front faces culled: every quad must render whole and the gaps between them stay clear. Without the table the first check fails ("a triangle crossed the restart after quad 0").

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:57:16 -05:00
Dean bc2f128ea4
Merge pull request #2655 from oneandonlydean/up2/target-key-proof
perf(agc): prove a render target's register clear keys instead of scanning them every draw
2026-10-11 01:55:58 +13:00
Rohan K 179c9b6014 fix(videoout): add throwing output status with VRR export 2026-10-10 18:14:49 +05:30
Adrià b69270dd95
Merge pull request #2713 from adriadam10/feat/gpl-background-lto
perf(agc): relink library pipelines with link-time optimization in the background
2026-10-10 14:36:43 +02:00
Dean da7429f684
Merge pull request #2678 from oneandonlydean/up2/single-pass-storage
perf(agc): move storage texels between the image and its tiled bytes in one pass
2026-10-11 01:36:32 +13:00
boykopovar 0bd2e4cb90 test(relinker): align module tests with nonrecursive discovery 2026-10-10 15:31:17 +03:00
Adrià Franch 8e73f6e73e perf(agc): relink library pipelines with link-time optimization in the background
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 14:24:45 +02:00
Dean cf8b129e27
Merge pull request #2670 from oneandonlydean/up2/pass-hazards
perf(agc): continue render passes across draws without hazards
2026-10-11 01:18:14 +13:00
virp-mta df131b9c39 fix(libkernel): maintain random device and file lock invariants in dup and dup2 2026-10-10 15:54:21 +04:00
Adrià Franch cb34140cfb docs(technical-debt): record dup and dup2 limits 2026-10-10 15:52:46 +04:00
Renan Pires fb34636f47 feat(libkernel): implement dup and dup2 2026-10-10 15:52:25 +04:00
Adrià 197ffac972
Merge pull request #2661 from adriadam10/feat/fixed-push-slots
perf(agc): give each graphics stage a fixed push constant slot with pipeline libraries
2026-10-10 13:50:19 +02:00
boykopovar f756225f09 docs(usage): add sce-module-path optional flag 2026-10-10 14:38:04 +03:00
Tharun Balaji 36bc9214cf fix(libkernel): return SCE errors from sceKernelFdatasync 2026-10-10 16:55:24 +05:30
Tharun Balaji 8839f6a1ba feat(libkernel): implement sceKernelFdatasync 2026-10-10 16:55:24 +05:30
boykopovar 336d481bff fix(relinker): default module path to input elf directory 2026-10-10 14:12:04 +03:00
boykopovar bec6d62b29 feat(relinker): add explicit guest module parent path option 2026-10-10 14:10:13 +03:00
alfalfa-star 4f9ddffce0 perf(agc): read a fast-cleared surface's guest bytes only when the import is compared
#2096 keeps a copy of a storage image's guest bytes so that Refresh can
compare memory the write watch does not cover. The host-import upload
path takes that copy only when the range is unwatched, but the DCC
fast-clear path took it on every upload. Reading the whole surface goes
through the flush hook, so each 64 KiB block of a surface that a unit
shadow covers recorded a publish and waited for the GPU.

The clear path now resolves the surface's host import first (the import
can unwatch the range, as a compared host-pointer import does) and takes
the copy only when the range is then unwatched, like the import path.
Write-watched memory, such as direct memory behind a dma-buf import,
skips it; a range that is unwatched later re-uploads instead of
comparing, as before #2096.

agc_driver_dcc_keys_first_write checks that a fast-cleared upload keeps
the copy exactly when its range is unwatched at that point.

PPSA14632 (LEGO Horizon Adventures) on Linux, RX 9070 XT: the flush hook
waited ~60,000 times per 10 s for these publishes (6.4 s), now ~3,500,
and presents rise from ~24 to ~100 per 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:05:34 +02:00
boykopovar 776f7738d4 fix(relinker): stop requiring host dependencies in guest module directories 2026-10-10 14:04:37 +03:00
boykopovar 400a496792 refactor(relinker): unify guest module diagnostics 2026-10-10 14:02:00 +03:00
Dean b5f5362d3d
Merge pull request #2647 from oneandonlydean/fix/guest-stack-host-margin
fix(libkernel): keep host stack room below guest thread stacks
2026-10-10 23:59:23 +13:00
boykopovar 41126bfa5b fix(relinker): restrict guest module discovery to adjacent directories 2026-10-10 13:59:11 +03:00
Dextroid17 b7e32b3648 fix(shader): decode the scalar aperture sources 235-238 instead of failing the shader 2026-10-10 06:57:12 -04:00
Dean Galvin db2cd3559e perf(agc): compare large stale draw snapshots on helper threads
A stale storage snapshot is revalidated by comparing every tracker block
stamped since it was taken. A title that binds buffers a dispatch writes
in place every frame (the whole declared range stamped, few pages really
changed) makes the graphics worker compare gigabytes per second.

Compares of 1 MiB or more are now split by block across a small pool of
helper threads (hardware threads / 8, from 1 to 4). The compare is memory
bound, so the worker's share roughly halves rather than dividing by the
thread count. A caller that finds the pool busy compares on its own
thread. Results and the patch-in-place rules are unchanged.

agc_driver_graphics_tests parallelCompareTests: per-span results on the
pool and serial paths, and two threads comparing at once.
2026-10-10 23:55:38 +13:00
Dean b0cccf20a0
Merge pull request #861 from jeffrey12cali/fix/linux-guest-arena
fix(guest-arena): place guest address space in the PS5 window on Linux
2026-10-10 23:55:28 +13:00
Dean Galvin 7c1b60c544 perf(agc): patch a stale storage snapshot's changed blocks in place
A stale storage snapshot was compared whole with the guest bytes and, on
any difference, copied whole into a new buffer, although few of the
tracker blocks stamped since the copy usually hold different bytes.

Only the 64 KiB tracker blocks stamped since the snapshot's generation
are compared now. When some differ and the cache holds the only
reference (no recorded draw binds the buffer), those blocks are copied
into it in place; otherwise the range is copied again as before.

agc_driver_recorder_tests drawSnapshotPatchTests: changed bytes in
several blocks and a whole changed block patch the snapshot nothing else
holds, an unchanged one is reused, and one a recorded draw still holds is
copied again with its bytes untouched.
2026-10-10 23:52:58 +13:00
Dean 2ba993a873
Merge pull request #1745 from AymanFE/fix/agc-hold-flip-behind-worker
Fix/agc hold flip behind worker
2026-10-10 23:52:07 +13:00
Dean Galvin 2688b76463 perf(agc): stage read and written buffer elements a dispatch sweeps
A written V# element bound in place in a host import makes every load a
PCIe round trip. A particle update that loads and stores a 10 MiB pool
(2048x64 threads over 131072 records of 80 bytes), above the 2 MiB written
window, took about 4.8 ms of GPU per frame.

An element the shader also reads (DescriptorBinding::bufferRead), written by
a direct dispatch whose threads times the V# stride cover at least half of
it, now takes device-local staging up to 16 MiB: that dispatch drops to
about 0.06 ms plus 0.9 ms of bulk copies. The coverage test keeps a kernel
that updates about 12k records of a 16 MiB pool in place, where staging all
of it would cost 1.3 ms of copies for a 0.08 ms kernel. Write-only
elements, indirect dispatches and raw (stride 0) buffers keep the 2 MiB
window.
2026-10-10 23:47:30 +13:00
Dean Galvin 25738ff67f perf(agc): move storage texels between the image and its tiled bytes in one pass
A storage write-back copied the image into a linear buffer and retiled
that buffer; an upload detiled into a linear buffer and copied it into
the image. With storage image access without a format, the retile now
reads each texel from the image through an unsigned integer view of the
element size, and the detile writes it there, so the linear buffer, its
copy and one barrier per move go away. The texels move bit for bit as
before, through the same tiling equations and windows.

This covers the block-unit windows of write-backs and uploads and the
whole-surface direct upload, for 2D, array and cube images.

agc_driver_recorder_tests singlePassTests: a first upload, a write-back
of new texels in every mip and a second upload over the stored memory
leave the images and guest memory byte for byte equal to the copies
through a linear buffer, in plain and write-watched memory.
2026-10-10 23:46:06 +13:00
Dean Galvin 2fb7a77acc feat(shader): note which guest buffer elements a shader loads from
DescriptorBinding gains bufferRead next to bufferWritten and bufferAtomic,
filled from the resource tracker's per-buffer read flag and kept in the
shader disk cache (format 24).
2026-10-10 23:45:38 +13:00
Dean 507f49fb33
Merge pull request #2669 from oneandonlydean/fix/windows-guest-read-refusal
fix(libkernel): read /dev/urandom through Windows pread again
2026-10-10 23:39:14 +13:00
Dean Galvin ecc14b0f66 perf(agc): continue render passes across draws without hazards
A recorded draw continued the open render pass only after a draw that
wrote no memory, so every draw with a storage write ended the pass and
paid two barriers. A draw now continues the open pass when its accesses
have no hazard (PassHazards) against those of the draws since the last
barrier. Address-based draws, draws through buffer device addresses and
draws with copied writes count as reading and writing any guest memory.

A draw of other attachments with no hazard ends the pass without a
barrier and begins its own without one, and a hazard break records the
begin barrier alone, towards every graphics stage, instead of the pass
end barrier plus the begin barrier. A pass with a depth attachment or
attachment proxies, or one followed by work after the pass, keeps both
barriers. APS5_FULL_BARRIERS keeps every barrier, as for the other merges.
2026-10-10 23:28:48 +13:00
Dean Galvin 0211ee7c73 feat(agc): render pass hazard tracker
PassHazards keeps the guest ranges, images and attachments the draws
since the last barrier read and wrote, and answers whether a new draw has
a RAW, WAW or WAR hazard against them. Address-based reads and unknown
writes count as touching any guest memory; attachments of the current
pass are ordered by rasterization and only conflict with other passes or
with sampled and storage uses. Unit tests in agc_pass_hazards.
2026-10-10 23:27:18 +13:00
Dean Galvin 766370108d fix(libkernel): read random devices in the Windows sceKernelPread
The Windows sceKernelPread stopped going through pread when it learned to
return errors, and with it lost the random device read, so a pread on
/dev/urandom reached ReadFile on a handle that is not a disk and failed
with ESPIPE. Read random devices first, as the Linux path does.

A pread into a read-only guest mapping now returns EFAULT instead of
throwing, matching Linux and the AIO read beside it, so the Windows
guest memory test checks for that return.
2026-10-10 23:26:37 +13:00
Scramblrrrr d5a396d927 fix(shader): preserve aliased embedded fetch attributes 2026-10-10 07:22:51 -03:00
Adrià Franch 8c802e5eb1 perf(agc): give each graphics stage a fixed push constant slot with pipeline libraries
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 12:19:31 +02:00
Joey Fisher 0fe61e4191 fix(agc): pick one priority path per mode and throw when it is refused 2026-10-10 04:14:08 -06:00
Joey Fisher 7add840f11 fix(agc): link the thread-priority test against libc for its personality routine 2026-10-10 04:14:02 -06:00
Joey Fisher 73e4afd951 test(agc): unit-test APS5_THREAD_PRIORITY parsing and the RLIMIT_RTTIME plan 2026-10-10 04:14:02 -06:00
Joey Fisher 22147dbbe6 fix(agc): lower the RLIMIT_RTTIME hard limit only when rtkit requires it
Read rtkit's MaxRealtimePriority and RTTimeUSecMax before touching the
limit, keep a hard limit that already satisfies rtkit, lower the soft
limit to at most half of the hard one, and log when the hard limit is
lowered. rtkit checks the hard limit, so it cannot be left alone when it
is above RTTimeUSecMax; the side effect is listed in TechnicalDebt.md.
Log the policy rtkit applied, SCHED_RR by default.
2026-10-10 04:14:02 -06:00
Joey Fisher a9c132a629 feat(agc): opt-in raised priority for the queue workers and the presenter 2026-10-10 04:13:57 -06:00
Dean Galvin ce274b5c0a perf(agc): reuse a stale storage snapshot whose bytes are unchanged
A draw's storage snapshot was copied again whenever the write tracker
reported a store over its range, although most such stores leave the
bytes as they were: in one title screen about 10k of 14k stale lookups per
10 s held the same bytes (3.5 GiB of copies).

A stale storage snapshot is now compared with the guest bytes, after the
caller's collect of the range, before it is dropped. When they are equal
it takes that collect's generation and is reused; any store after the
collect is stamped newer and fails the next check, as for a fresh copy. A
registry change still drops it without reading, and vertex and index
snapshots are dropped as before.
2026-10-10 23:13:33 +13:00
Dean Galvin fef67a4b21 perf(agc): prove a render target's register clear keys instead of scanning them every draw
materializeRegisterClear read the target's DCC keys with CurrentDccKeys on
every draw into a resident target with metadata: a full AllKeysEqual scan
of the key range (52 KiB for a 2432x1368 RGBA8 target), about 440k scans
per 10 s and 7.2% of the queue 0 worker's CPU time in one level.

ProvedCurrentDccKeys answers CurrentDccKeys from a proof kept with the
resident image (DccRangeProof: the key range, the keys and the write
generation collected before the scan), the rule ProvedClearKeys already
applies to a storage image's own keys: the proof holds while the key range
is unstamped since that generation (CollectWrites first, then
UnchangedSince), and a scan becomes the proof only when it read the bytes
(not the pending store memo) and no recorded work still writes them. Every
key writer stamps the range, so a store, a pending result or another key
range always scans again. The proof is used under GuestMemory::GpuMutex
only, and not with APS5_NO_KEY_FAST_PATH.

agc_driver_recorder_tests: an unchanged range is proved, and a key store
stamp, a CPU write, another range or address, and a pending key fill each
force a scan; the fill's result is proved once its batch finished.
2026-10-10 23:11:16 +13:00
Dean Galvin 765619a00b perf(agc): sub-allocate small host buffers from shared memory blocks
Every small host buffer (size classes below 1 MiB: draw and dispatch data,
copied regions, snapshots) had a VkDeviceMemory of its own. When the pool
missed, the worker paid a vkAllocateMemory and vkMapMemory, and the release
thread a vkUnmapMemory and vkFreeMemory, for each one. The frees also stall
the worker's vkQueueSubmit in the driver.

A host-visible buffer of a size class now gets its own VkBuffer bound into a
slot of a shared block (2 MiB, or 8 slots for the large classes) per memory
type, size class and device-address use, mapped once. Releasing it destroys
only the VkBuffer and returns the slot; a block is freed when it empties and
its slab already keeps an empty one. A slot is used only when the buffer's
alignment and the non-coherent atom divide its size class, so the slot
offset is valid for the bind and Invalidate covers exactly the slot. The
pool still retains released buffers by class as before; only what backs
them changed.
2026-10-10 23:05:21 +13:00
Dean Galvin 58d1f5ab18 fix(recompiler): split descriptor webs whose Phis sit in different blocks
A sample whose T# is chosen in one if/else and whose S# is chosen in a later one has descriptor Phis in two blocks. The web walk required every Phi of the tuple to sit in one block, so it gave up and the plan threw "GetImageResource dword 0 is not a valid runtime value". The walk now splits at the Phis of the latest block in program order, and Phis of earlier blocks pass through each edge unchanged until the walk reaches their block.
2026-10-10 23:05:11 +13:00
Dean Galvin 5d888abd75 fix(agc): wake the flip hold on worker progress
The hold no longer polls every millisecond and has no switch to turn it
off. A held submission waits on the driver's condition variable until no
flip is ahead of it, or until queue 0 waits for memory that only the
title can store. The queue 0 worker reports the second case from its
memory and rewind waits, and the worker that reaches a flip wakes the
holders.

agc_driver_flip_tests: a flip held behind a rendering wait is released
when the worker goes on to wait for a label only the title stores, with
no further submission.
2026-10-10 23:04:30 +13:00
Dean Galvin 2485915a03 perf(agc): skip the resource-cache key and lookup for address-based draws
A draw whose stages bind a BDA table or a fault buffer builds resources
that need completion work, so noteReusable never keeps them and the shared
resource cache never holds an entry such a draw could hit. Building the
content key and probing the cache for each of them was pure cost. Those
draws now skip both (ShaderResources::NeverReusable) and count as
uncacheable.
2026-10-10 23:02:52 +13:00
Adrià a29ef59219
Merge pull request #2645 from adriadam10/feat/gpl-dynamic-rendering
perf(agc): render with dynamic rendering when pipelines come from libraries
2026-10-10 12:00:40 +02:00
AymanFE 8cd0904f92 fix(agc): hold a flip submission until the worker has consumed the previous one
A title that paces itself on pending flips assumes what hardware gives it:
the command processor consumes a submitted buffer at once, so a pending flip
is a frame whose commands have been read and that only waits for the display.
The queue worker is slower than that. With three flips pending it can still be
recording the oldest frame while the title rewrites that frame's slot of a
three-deep ring of per-frame memory for the frame after next, and the draws
are then recorded with the later frame's (or half-written) constants.

A submission on queue 0 that carries a flip now waits until the worker has
reached the flip of every earlier one. The wait ends early when queue 0 is
blocked on memory that no running or pending work writes, since only the
title can end that wait. APS5_NO_FLIP_HOLD=1 submits as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MPYE7P9ob12aAE1H4JtHF
2026-10-10 22:58:25 +13:00
Dean Galvin cf85a72024 fix(guest-arena): throw when the Linux reservation cannot be placed
Throw when /proc/self/maps cannot be read or parsed, and when the kernel
places a reservation chunk at another address (MAP_FIXED_NOREPLACE
treated as a hint). Remove the unused PageSize and keep the POSIX-only
headers in the non-Windows block.
2026-10-10 22:56:07 +13:00
Dean Galvin d9f8400351 fix(libkernel): answer munlock from the guest mapping state on Linux
An unmapped range inside the guest arena stays a PROT_NONE host
reservation, so host munlock succeeds on it. Check the guest mapping
state first, as msync does, and return ENOMEM for ranges the guest
has not mapped or reserved.
2026-10-10 22:56:07 +13:00
jeffrey12cali c4062623bd test(guest-arena): keep the fixed-mapping probe on Linux only
CheckUnmappedArenaRangeStaysReserved uses mmap, PROT_READ, PROT_WRITE,
MAP_FIXED_NOREPLACE and EEXIST directly, so the Windows build fails to compile it.
The probe exists to show that an unmapped arena range still rejects a hostile
MAP_FIXED_NOREPLACE mapping, which is Linux-specific behaviour.

Guard the function and its call site with __linux__. The other tests in the file
compile on both platforms.
2026-10-10 22:56:07 +13:00
jeffrey12cali a30da639fd fix(guest-arena): leave address-space accounting to the caller on reset
The Linux implementation of GuestArenaReset released the range in addition to
resetting the memory, while the Windows implementation only resets the memory and
leaves accounting to the caller. Two call sites already release explicitly after a
reset, so every one of them released the same range twice: sceKernelMunmap through
ArenaForget, and GuestHeap::release through GuestArenaRelease.

The two releases acquire the arena lock separately. Contains is span-based, so the
second release still runs, and Release erases every overlapping entry. A thread that
allocates the range between the two calls therefore has its entry erased, and the arena
hands the same guest address range out twice.

Delete the release from the Linux reset so both platforms restore the documented
contract. Every existing caller already pairs the reset with an explicit release.
2026-10-10 22:56:07 +13:00
jeffrey12cali e4e0702946 fix(guest-arena): place guest address space in the PS5 window on Linux
The arena constructor was Windows-only, so on Linux Available() was false: the guest heap fell back to the host allocator and direct memory landed wherever the kernel pleased. Titles that require a low virtual address rejected the mapping and re-issued the identical request, which surfaced as a start-up assert inside their own allocator.

Seed the window from the mappings that already exist instead of reserving it up front, because a PROT_NONE reservation of the whole range starves the kernel's own top-down mmap, which picks addresses just below the stack inside that range. Commit, reset and set-protection become portable so the arena owns its used ranges on both platforms, and fixed mappings are checked against the arena's used ranges rather than against EEXIST from a reservation.

The window-placement and no-overwrite checks in guest_memory were compiled only for Windows; they now run on Linux too, and the window check fails without this change.

Fixes #692
2026-10-10 22:56:07 +13:00
Adrià Franch 0c20cab656 perf(agc): render with dynamic rendering when pipelines come from libraries
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 11:45:25 +02:00
Dean Galvin 84d90152b4 fix(libkernel): keep host stack room below guest thread stacks
Since guest threads get exactly the stack size they request, host code
that a guest thread calls runs on that small stack too. sceAgcCreateShader
reaches Driver::RegisterShader, whose frame alone is about 50 KiB, so a
title whose job threads ask for 48 KiB overflows the stack (#2603).

Each guest thread now gets a fixed 1 MiB of host stack below the range it
asked for. The guest still sees the requested size and address range
through scePthreadAttrGet and sceKernelIsStack; only host calls made from
the thread use the extra room. Running the prepared-shader driver tests on
a limited main-thread stack needs between 128 and 192 KiB for shader
registration, Vulkan setup included, so 1 MiB leaves several times that.

Switching to a separate host stack at each HLE entry point would need a
trampoline on every export that may go deep, handling of stack-passed
arguments and unwinding across the switch, and a list of which exports
qualify. A margin below the guest range covers every host call with no
per-export list.

On Windows the committed size was the requested size, and the margin
below it depended on the executable's default stack reserve; requests at
or above that reserve had none. The commit now includes the same margin.
macOS does not run guest threads.

guest_pthread_stack now also calls host code that uses 256 KiB of stack
below each thread's guest range; without the margin it crashes on the
16 KiB thread.

Fixes #2603
2026-10-10 22:41:03 +13:00
Adrià be403084c6
Merge pull request #1141 from nicolasabosch/feat/kernel-pthread-cancel
feat(libkernel): implement thread cancellation
2026-10-10 11:40:09 +02:00
Adrià 663cc42c85
Merge pull request #2636 from adriadam10/feat/gpl-libraries
perf(agc): link graphics pipelines from per-stage libraries
2026-10-10 11:39:12 +02:00
Adrià 6675e60bf1
Merge pull request #2409 from danzaio/feat/rudp-activate
feat(libSceRudp): implement sceRudpActivate
2026-10-10 11:35:58 +02:00
Adrià c84694adbb
Merge pull request #1905 from Raghav314/fix/agc-address-builds-gpu-access
fix(agc): address-based builds map only memory mapped for the GPU
2026-10-10 11:35:38 +02:00
Nicolas Abosch ef9d0dd7d2 chore(libkernel): drop the pthread_cancel comment 2026-10-10 11:32:09 +02:00
Nicolas Abosch 3acca27f27 feat(libkernel): implement thread cancellation
scePthreadCancel and pthread_cancel threw, scePthreadTestcancel did
nothing and the cleanup handler exports did not exist.

A cancel request is now recorded on the thread and acted on at
scePthreadTestcancel, the condition variable waits, scePthreadSem and
sem waits, scePthreadJoin and the sleeps, and under their POSIX names.
A thread blocked in one of the waits is woken; a condition wait takes
its mutex back before the thread exits. The thread exits with
PTHREAD_CANCELED through scePthreadExit, which now runs the handlers
of __pthread_cleanup_push_imp and __pthread_cleanup_pop_imp.
scePthreadSetcancelstate and scePthreadSetcanceltype reject unknown
values, and pthread_setcanceltype is added.

Constants, the handler node layout and the order of events follow
FreeBSD libthr. A sleep is not interrupted, file and socket calls are
not cancellation points and the asynchronous type acts like the
deferred one except at the two set calls (TechnicalDebt). New test:
guest_pthread_cancel.
2026-10-10 11:32:09 +02:00
Adrià 948a526c23
Merge pull request #407 from Pouare514/feat/deathloop-loading
feat(libs): Deathloop loading support (Ampr, NetCtlApDialog + stubs)
2026-10-10 11:29:40 +02:00
Adrià 00d4e3a540
Merge pull request #976 from Saibamen/ci/release-parity
ci(release): match PR CI Vulkan and Windows SSL setup
2026-10-10 11:29:15 +02:00
Adrià 1052fcc7e6
Merge pull request #2593 from eliasbruno124-dev/fix/agc-bulk-resource-unavailable
fix(libSceAgcDriver): report unavailable bulk resource registration
2026-10-10 11:29:12 +02:00
Adrià aad13ac11b
Merge pull request #1147 from alfalfa-star/perf/agc-staging-pool-heap-budget
perf(agc): size the device staging pool from the device-local heap
2026-10-10 11:28:29 +02:00
Adrià cb6870f965
Merge pull request #2538 from husseinkad/fix/windows-stat-file-identity
fix(libkernel): report a stable file identity from stat and fstat on Windows
2026-10-10 11:26:32 +02:00
Adrià Franch 0a04c8658c perf(agc): link graphics pipelines from per-stage libraries
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 11:25:23 +02:00
Adrià cd73e149b3
Merge pull request #1290 from SirDarky/fix/shader-mac-legacy-denormals
fix(shader): flush v_mac_legacy_f32 denormals as measured on gfx1010
2026-10-10 11:23:53 +02:00
Adrià 3afc78464c
Merge pull request #2543 from overlordxrz-source/feat/libkernel-kill
feat(libkernel): implement kill
2026-10-10 11:21:08 +02:00
Adrià b4a4133c0c
Merge pull request #2530 from hazzardouslysolid/fix/png-truncated-transparency
fix(png): bound transparency chunk detection to the input
2026-10-10 11:20:34 +02:00
Adrià b750211412
Merge pull request #1776 from Celegans12/feat/shader-lds-beyond-device-limit
feat(shader): implement compute LDS beyond the device's shared memory limit
2026-10-10 11:20:13 +02:00
Adrià 309e0675f6
Merge pull request #1415 from TheAggie/fix/agc-sampler-aniso-override
fix(agc): accept the sampler ANISO_OVERRIDE bit
2026-10-10 11:19:53 +02:00
Adrià 1138fa96f4
Merge pull request #2554 from 22alfbassett/fix/kernel-sync-recorded-paths-linux
fix(libkernel): flush only recorded paths in sceKernelSync on Linux
2026-10-10 11:17:59 +02:00
Adrià 95fe14235a
Merge pull request #2536 from orbz22/fix/audioout2-queue-port-buffers
fix(audioout): play every AudioOut2 port buffer set between pushes, one per grain
2026-10-10 11:17:19 +02:00
Adrià 11cb1b75ab
Merge pull request #2397 from NahuelGenchi/fix/libc-posix-memalign-huge
fix(libc): return ENOMEM from posix_memalign for sizes the default heap rejects
2026-10-10 11:15:44 +02:00
Adrià ebe6c180bf
Merge pull request #2594 from morten-holm/pr/macos-clear-pie
fix(relinker): leave MH_PIE clear in the macOS executable
2026-10-10 11:15:15 +02:00
Adrià Franch 0c6be3e23f docs(TechnicalDebt): move the sceRudpActivate line away from the end of the section 2026-10-10 11:13:57 +02:00
Adrià a0a650884b
Merge pull request #2412 from MathiasDevelopes/feat/libscepsml-module
feat(libScePsml): build libScePsml from the libScePsml_debug source
2026-10-10 11:13:55 +02:00
danzaio d0407a808d feat(libSceRudp): implement sceRudpActivate
Astro's Playroom (PPSA01325) calls sceRudpActivate during start-up, where the throwing stub stopped it. The host has no reliable-UDP stack to activate, so the export returns success and does nothing, matching the OK-returning stubs shadPS4 keeps for the whole library. The guest_offline_imports test now checks the success path with and without sceRudpInit, and still checks that the sceRudpGetStatus sibling throws and writes nothing.
2026-10-10 11:13:46 +02:00
Adrià Franch 43cc101910 docs(technical-debt): record the lossy Windows file identity fold
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 11:08:15 +02:00
Hussein Kadhim 9b5be73a99 fix(libkernel): keep stat working when a handle has no file identity
Leave the Windows identity fields at their stat values when
GetFileInformationByHandle fails on a handle whose basic information
could be read, instead of failing the whole call.
2026-10-10 11:08:10 +02:00
Hussein Kadhim 0b1941b313 fix(libkernel): report a stable file identity from stat and fstat on Windows
st_ino was always 0 and st_dev differed between stat (drive number) and
fstat (0), so the usual a.st_dev == b.st_dev && a.st_ino == b.st_ino
identity check gave wrong answers. Read the volume serial, the file index
and the link count from the file handle, which works the same for path and
descriptor lookups.

Fixes #2296
2026-10-10 11:08:09 +02:00
overlordxrz-source 9a70477170 feat(libkernel): implement kill
ProsperoStore (PPSA99000) imports kill from libkernel and stops at it on
current main. Its crash reporter resets a crash signal to SIG_DFL and
sends it again with kill(getpid(), signal).

kill follows FreeBSD's kern_kill and killpg1 for the only guest process:
EINVAL for signals outside 0 to 128, signal 0 only checks the target,
and the caller's own pid, 0 and minus its pid deliver through raise.
Any other pid, and -1, which skips the caller, report ESRCH.
2026-10-10 11:06:12 +02:00
raghav314 c11a9cb59f fix(agc): address-based builds map only memory mapped for the GPU
The registry records whether a range was mapped or protected with GPU
access (0x10/0x20), and an address-based build leaves out ranges without
it, as the console's GPU page tables do. The main image is registered
without GPU access; the title's own mprotect with GPU bits adds it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:34:34 +05:30
Adrià 3d1a7d90c7
Merge pull request #2619 from oneandonlydean/fix/carry-2525
fix(relinker): skip repeated DT_NEEDED libraries
2026-10-10 11:01:22 +02:00
Adrià 2f3b5046e5
Merge pull request #1492 from Celegans12/feat/agc-dual-source-blending
feat(agc): implement dual-source blending from the MRT1 export
2026-10-10 11:01:16 +02:00
Adrià 4b584d1c37
Merge pull request #2349 from Pipodi/fix/formatted-gpu-buffer-helper
fix(recompiler): emit a GPU-selected formatted buffer access through one shared function
2026-10-10 11:00:10 +02:00
Adrià 412fa8b06f
Merge pull request #1864 from fisherjoey/fix/agc-compute-gate-capture
fix(agc): land cross-queue waits and capture the gated compute group at the gate
2026-10-10 10:57:52 +02:00
Scott Schuster 1a778f7506 fix(agc): decide ANISO_OVERRIDE single-level images from the T#'s own levels
The hardware turns anisotropy off under ANISO_OVERRIDE when the T#'s BASE_LEVEL equals its LAST_LEVEL. The view's level count is taken after LAST_LEVEL is clamped to MAX_MIP, so a T# with BASE 0, LAST 3, MAX_MIP 0 counted as single-level here while the hardware keeps anisotropic filtering for it (measured by @adriadam10 on the hardware oracle). The pairing now reads BASE_LEVEL and LAST_LEVEL from word 3 (DescriptorSingleLevel).

The per-draw path gets a test, agc_driver_image_sample_aniso_override: one ANISO_OVERRIDE sampler shared by two images in a dispatch, with single-level, mipmapped, mixed, and LAST_LEVEL > MAX_MIP descriptors, checking which pairings run (with their samples) and which are refused as mixed. With the old view-based check the LAST_LEVEL > MAX_MIP pairing is refused.

applyAnisoOverride reads the APS5_NO_SAMPLER_CACHE switch through the same cached flag as addImageBinding instead of calling getenv per sampler per draw.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:57:02 +02:00
Scott Schuster 17d9efc290 fix(agc): turn anisotropy off for single-level images under ANISO_OVERRIDE
With ANISO_OVERRIDE the texture unit disables anisotropic filtering when the
sampled view has a single level. Each draw now records, per sampler, whether
its paired images are single-level or mipmapped. A sampler with the bit and an
anisotropic filter whose images are all single-level is bound as the same S#
with point or linear filtering in place of the anisotropic filters, taken from
the sampler cache. One sampler descriptor serves every image paired with it,
so a sampler paired with both kinds in one draw still throws. Samplers of
mipmapped images keep their anisotropy, as on the hardware.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:57:02 +02:00
Scott Schuster d8bb441118 fix(agc): accept the sampler ANISO_OVERRIDE bit
Mesa sets ANISO_OVERRIDE (S# word 2, bit 29) on every GFX10+ sampler
unless aniso_single_level is on; it turns anisotropic filtering off for
single-level views. Samplers carrying it were rejected. Accept and
ignore it: host samplers are built from the S# alone and shared between
images, so single-level views keep the sampler's anisotropy. The gap is
recorded in TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:57:02 +02:00
Adrià Franch 60251f9205 docs: describe LDS in device memory in ARCHITECTURE and TechnicalDebt
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 10:56:56 +02:00
Celegans12 7144bb57ee feat(shader): implement compute LDS beyond the device's shared memory limit
Route oversized compute LDS through a per-workgroup storage buffer.
Retain native shared memory for programs that fit the device limit.
Carry the spill stride through prepared shader results and dispatches.
Preserve the stride in the full-result codec and its round-trip fixture.
Keep the Linux RecompileResult size guard aligned with the added field.
Exercise interleaved workgroups and the device-limit boundary.
This topic contains only the LDS change and its reviewer-requested repair.
The base includes upstream's separately merged NaN result correction.
2026-10-10 10:56:56 +02:00
Marcus 683ea37935 fix(shader): flush v_mac_legacy_f32 denormals as measured on gfx1010
VOP2 0x06 measured the same as VOP3 0x140 on gfx1010 (RX 5700 XT) in
wave32 and wave64, IEEE 0 and 1 and f32 denormal modes 0 to 3: the
product is rounded before the add, f32 denormal sources, product and
result are flushed in every mode, and a zero factor gives a +0 product.
It now shares the v_mad_legacy_f32 translation with the accumulator as
the addend, and f32DenormalFlushFor returns 3 for it as well. A new
execution test pins the measured results of its VOP2 and VOP3 forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:54:23 +02:00
Adrià c9f9e0f139
Merge pull request #2627 from oneandonlydean/fix/carry-2580
fix(agc): defer registered compute shaders without specials to dispatch
2026-10-10 10:53:29 +02:00
Adrià 69e9a2685a
Merge pull request #2605 from elsi06/fix/relinker-self-guest-modules
fix(relinker): reject guest modules in SELF containers
2026-10-10 10:52:52 +02:00
Adrià 695e0b928a
Merge pull request #1551 from MarcZX100/fix/precise-subtick-polls
fix(windows): use precise waits in sub-millisecond polling loops
2026-10-10 10:52:48 +02:00
Adrià 425421276a
Merge pull request #1640 from morten-holm/pr/shader-select-mask
fix(shader): keep s_cselect_b64 of two masks as a lane bit and fold constant masks
2026-10-10 10:51:35 +02:00
Adrià e11c7bef4e
Merge pull request #2623 from oneandonlydean/fix/savedata-cancel-2598
fix(savedata): export sceSaveDataCancel
2026-10-10 10:50:53 +02:00
Adrià 4997f85ad3
Merge pull request #2620 from oneandonlydean/fix/carry-2423
fix(libkernel): return errors from file operation failures
2026-10-10 10:50:33 +02:00
Adrià 68587c34db
Merge pull request #2616 from oneandonlydean/fix/carry-2556
fix: skip zero-length memcpy calls
2026-10-10 10:50:12 +02:00
Adrià 9d249f365e
Merge pull request #2613 from oneandonlydean/fix/carry-2564
fix(libkernel): return every command-line argument as UTF-8 from getargv on Windows
2026-10-10 10:49:51 +02:00
Adrià a56b44a13c
Merge pull request #1735 from TheAggie/feat/agc-color-target-4kb-xor
feat(agc): render into XOR-swizzled color targets with a pipe/bank XOR, and into SW_4KB_S_X/D_X
2026-10-10 10:49:43 +02:00
Adrià 1de7e438fa
Merge pull request #2626 from oneandonlydean/fix/carry-2578
fix(agc): render into one slice of a 2D array color target
2026-10-10 10:48:29 +02:00
Adrià 4b6abf0381
Merge pull request #2625 from oneandonlydean/fix/carry-2577
feat(agc): sample with DISABLE_CUBE_WRAP through non-seamless cube samplers
2026-10-10 10:47:31 +02:00
Adrià d66133ac18
Merge pull request #2622 from oneandonlydean/fix/carry-2329
fix(libc): open fopen and freopen paths through the wide CRT on Windows
2026-10-10 10:47:07 +02:00
Adrià 970c3059c2
Merge pull request #2617 from oneandonlydean/fix/carry-2553
fix(libSceFont): report vertical glyph metrics
2026-10-10 10:46:39 +02:00
Adrià 8fded89e6b
Merge pull request #1803 from tv7/fix/mprotect-guest-module-images
fix(libkernel): reprotect bundled guest module images on Windows
2026-10-10 10:45:37 +02:00
Adrià 4fbf6ca5a3
Merge pull request #1960 from Raghav314/fix/agc-import-leaves-pages-unarmed
fix(agc): host imports write-protect only pages a collect already protects
2026-10-10 10:45:04 +02:00
Adrià 874c144712
Merge pull request #1909 from TheAggie/feat/libkernel-mmap-aligned-super
feat(libkernel): accept MAP_ALIGNED_SUPER in mmap
2026-10-10 10:44:57 +02:00
Mini 781e049e50
Merge branch 'boykopovar:main' into pr/videoout-test-driver 2026-10-10 01:43:53 -07:00
Adrià c5d77d6bd5
Merge pull request #2276 from hugodearaujo/perf/recompiler-dominance-lookups
perf(recompiler): look up dominance by binary search and track visited blocks in a bitmap
2026-10-10 10:43:47 +02:00
Adrià 8f442a7554
Merge pull request #2615 from oneandonlydean/fix/carry-2597
fix(libc): export the remaining exception entry points natively on Windows
2026-10-10 10:42:24 +02:00
Adrià 919c49b964
Merge pull request #2612 from oneandonlydean/fix/carry-2579
fix(libc): end the process without detach routines in _Exit on Windows
2026-10-10 10:41:16 +02:00
LuisBiceps 63a20d672b refactor(libc): move the getifaddrs test and TechnicalDebt entry away from lines other pull requests change
The guest_interfaces test now follows guest_thread_callback_abi instead of guest_errors, and the TechnicalDebt entry follows the libc SSE4a trap emulation entry instead of ending the Functional list, where other open pull requests add theirs.
2026-10-10 16:41:11 +08:00
Alex Collini 8dbea2c654 fix(recompiler): emit a GPU-selected formatted buffer access through one shared function
A formatted buffer load or store through a GPU-selected descriptor still
emitted the switch over every buffer format inline, at each access. A
Ghost of Yotei compute pass with ~300 such accesses compiled to 37M SPIR-V
words, and its pipeline took 40 s or more to create.

The switch is now emitted once per component count, direction, d16,
coherence, kind and stop mode, as a SPIR-V function that takes the
descriptor fields, the offsets and the access's PC. When faults stop the
invocation, the helper returns whether one did and the caller stops there.
BDA faults record the PC from BdaInstructionPc, the access's own PC or the
one a shared helper takes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:40:05 +02:00
Dean 73a35466cd
Merge pull request #2628 from oneandonlydean/fix/carry-2606
test(agc): skip agc_driver_prepared_shaders_deferred_undecodable without a Vulkan device
2026-10-10 21:39:42 +13:00
Adrià 05e884ca08
Merge pull request #2618 from oneandonlydean/fix/carry-2549
fix(relinker): leave zero-filled PT_LOAD memory out of Windows files
2026-10-10 10:38:10 +02:00
Adrià 7cbd0fcbac
Merge pull request #2614 from oneandonlydean/fix/carry-2582
test(font): isolate guest_font system font lookup
2026-10-10 10:37:25 +02:00
Adrià 444edc3652
Merge pull request #1819 from TheAggie/feat/agc-pixel-stipple-fixed-point
feat(agc): accept the LINE_STIPPLE_TEX and POS_FIXED_PT pixel inputs
2026-10-10 10:37:00 +02:00
AlxcBTW 8b691387cb test(agc): skip agc_driver_prepared_shaders_deferred_undecodable without a Vulkan device
The --deferred-undecodable mode registers shaders through a Vulkan
device but, unlike --deferred, did not check for one first. On the
Windows CI runner, which has no Vulkan driver, vkCreateInstance returns
VK_ERROR_INCOMPATIBLE_DRIVER and the test fails instead of skipping, so
the windows job on main has failed since e5b32bb4. It now returns
VulkanTestSkipped like the other modes.
2026-10-10 21:31:34 +13:00
MarcZX100 54a9018514 fix(windows): use precise sleeps for sub-millisecond polling
Co-authored-by: Shaan <shaansahai2007@gmail.com>
2026-10-10 08:30:28 +00:00
MarcZX100 9d89f7b787 test(libc): cover precise sleep helper 2026-10-10 08:30:28 +00:00
Celegans12 b8cc4adb3b feat(agc): implement dual-source blending from the MRT1 export
CB_BLENDn_CONTROL factors 15-18 (BLEND_SRC1_COLOR, BLEND_INV_SRC1_COLOR,
BLEND_SRC1_ALPHA, BLEND_INV_SRC1_ALPHA) threw "unsupported blend
factor". They blend MRT0 with the pixel shader's MRT1 export as the
second source, as RADV and radeonsi program it.

DecodeState maps them to the VK_BLEND_FACTOR_SRC1_* factors and accepts
them only with pixel exports to slots 0 and 1, color writes to slot 0
alone, an MRT1 export with MRT0's export format and shader mask, an
ADD, SUBTRACT or REVERSE_SUBTRACT operation and an identity component
order. The blend is draw state, so the specialized module of the
registered pixel shader moves its MRT1 output to location 0 index 1,
which ValidateShaders requires; pipelines need dualSrcBlend, now enabled
when present. The request field dualSourceBlend is in the module key,
the result memo, the draw key and the serialized request (version 15).
2026-10-10 10:29:00 +02:00
Joey Fisher db1bd553c7 fix(agc): drop the switches that turned the wait and capture fixes off 2026-10-10 10:27:59 +02:00
Joey Fisher e802fd4047 test(agc): check that a gated dispatch reads its table after the cross-queue label lands 2026-10-10 10:27:59 +02:00
Joey Fisher f89bf1d417 fix(agc): resolve a compute queue's dispatch group when its wait passes 2026-10-10 10:27:59 +02:00
Joey Fisher de93d3e7b0 fix(agc): land cross-queue waits passed on recorded labels before guest reads 2026-10-10 10:27:59 +02:00
Adrià 6cc3358332
Merge pull request #2184 from EdouardSence/fix/libkernel-pthread-tid
fix(libkernel): start the pthread object with the thread id
2026-10-10 10:27:44 +02:00
hugodearaujo 82853352fe perf(recompiler): look up dominance by binary search and track visited blocks in a bitmap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:26:03 -03:00
Mini d43c2d8750
Merge branch 'boykopovar:main' into pr/videoout-test-driver 2026-10-10 01:24:06 -07:00
LuisBiceps 5c0610f334 feat(libc): keep getifaddrs flags consistent with their addresses on Linux
Drop IFF_POINTOPOINT from an address without a peer and compute an IPv4 broadcast address the host omits from the netmask, since FreeBSD always provides the address when the flag is set. Check zero port, flowinfo and padding in the test.
2026-10-10 10:23:55 +02:00
LuisBiceps a09b67b142 feat(libc): report getifaddrs errors through errno and handle Windows edge cases
Return -1 with the FreeBSD errno for a null list and for expected host and allocation failures, as getcwd does. On Windows, give an unspecified prefix length a host mask, leave PPP and tunnel adapters without broadcast or point-to-point flags since their peer address is not reported, fall back to if<index> for long NDIS names, and bound the adapter query retries. Compare every entry with the host's own list in the test.
2026-10-10 10:23:55 +02:00
LuisBiceps 7cd185ec79 feat(libc): implement getifaddrs and freeifaddrs
List the host's IPv4 and IPv6 addresses in FreeBSD's struct ifaddrs layout, with FreeBSD sockaddrs and interface flags, from getifaddrs on Linux and GetAdaptersAddresses on Windows. The list is one allocation, so freeifaddrs is a single free.
2026-10-10 10:23:55 +02:00
Lexroid b1a14c6f36 fix(libkernel): unregister guest module images in dlclose and propagate failures
Move the image unregistration out of the Module destructor into
dlclose_nid_postfix. It runs while the handle is still registered, so a
failure (the image stays leased by GPU work) propagates to the caller and
leaves the module loaded and usable. Images shared by another open
handle stay registered until the last handle closes.

guest_memory now checks that dlclose under a held lease throws and keeps
the module, its symbols and its protection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:23:50 +02:00
Lexroid 57c179c74d fix(libkernel): unregister guest module images when they are unloaded
A .guest.prx image registered by sceKernelMprotect stayed in the guest
allocation registry after dlclose freed it, so its dead ranges blocked
later mappings at that address and could reach GPU builds.

The Windows module destructor now unregisters the image before
FreeLibrary. Unregistering waits for outstanding leases on the image like
unmap and protect do; if the wait fails the module stays loaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:23:42 +02:00
Lexroid 9f1d7b0516 fix(libkernel): reprotect bundled guest module images on Windows
On Windows, sceKernelMprotect accepted only the executable's image and threw
"Memory protection of a foreign image is not supported" for every other
image. Bundled title modules are relinked into DLLs named <module>.guest.prx,
so a title that reprotects its own module pages failed. Dying Light 2's
bundled libNRD does this at start-up (#1794).

DoMprotect now also accepts images whose file name ends in .guest.prx, and
registers their committed pages like the executable's. Other images are
still refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:23:42 +02:00
Doston Abdullayev 1fd723f21f fix(libkernel): return errors from file operation failures
On Windows, sceKernelPread and sceKernelPwrite called the POSIX pread and
pwrite wrappers, which throw on every failure, so a bad descriptor, a
negative offset or a write to a read-only descriptor aborted the process
instead of returning an error as the Linux build does. ftruncate and
sceKernelFtruncate threw on any host failure on both platforms.

Give the Windows sceKernelPread and sceKernelPwrite the same checks and
SceErrorFromErrno returns as the Linux ones, and accept a zero-length
transfer with a null buffer. Report a positioned transfer on a handle
opened without the needed access as EBADF instead of EIO. Return EINVAL
from ftruncate for a negative length and for a descriptor opened without
write access, as FreeBSD does, and pass other host errors to the guest.

Fixes #2423
2026-10-10 21:23:30 +13:00
xXPBSXx eb18595e81 fix(libc): open fopen and freopen paths through the wide CRT on Windows 2026-10-10 21:23:30 +13:00
Adrià 85d16bcc23
Merge pull request #2347 from Pipodi/fix/sampled-heap-capacity
fix(recompiler): hold 64 images in a sampled image heap
2026-10-10 10:23:23 +02:00
nyavana 8b008a3e96 test(relinker): cover repeated guest module dependencies
Generate guest PRX dependencies with adjacent and separated repeats, equal names at distinct string offsets, and invalid-name controls. Check acceptance for Linux and Windows conversion and first-seen dependency order in ELF outputs.

Depends on the production fix by Hannah Lyons (babyhuey), c1a6696872153b8e41608f4cc8ab9a0d36f1d206. Written with AI assistance.
2026-10-10 21:23:19 +13:00
MarcZX100 0e838c5be3 fix: skip zero-length memcpy calls 2026-10-10 21:23:19 +13:00
Yassine a44e70957a fix(libSceFont): report vertical glyph metrics
sceFontGetCharGlyphMetrics and sceFontGetRenderCharGlyphMetrics set the
vertical bearing and advance to zero although the glyph is loaded with
FT_LOAD_VERTICAL_LAYOUT. The library's own text writing steps the pen by
that vertical advance, so every character of vertical text was placed on
the previous one.

The vertical metrics now follow the FreeType driver's metrics of a
rendered glyph: FreeType's vertical advance, and for a face without
vertical metrics a bearing of half the horizontal advance left of the
horizontal bearing and of half the advance left over by the glyph height.

guest_system_font checks every metric of a square glyph at 100 pixels.

(cherry picked from commit 04dd69f806379df8b52cfdeb2979f2595973a9b3)
(cherry picked from commit 11f6f9e954756ee8d4a3fc2be574ab3b57ecd7c5)
2026-10-10 21:23:19 +13:00
Yassine 6158444f71 fix(relinker): leave zero-filled PT_LOAD memory out of Windows files
WindowsPeWriter stored every PE section with SizeOfRawData equal to its
virtual size, so the zero-filled tail of a PT_LOAD segment (p_memsz above
p_filesz, the .bss) was written to the executable byte for byte. A segment
with 256 MiB of .bss produced a 269 MB .exe, while the Linux output of the
same image is under 5 KB.

Each section is now stored up to its last non-zero byte, aligned to the file
alignment, and VirtualSize keeps the full size. The PE loader zero-fills the
part of a section beyond SizeOfRawData (Microsoft PE format, section table:
SizeOfRawData). A section with no non-zero byte gets no raw data and a zero
PointerToRawData.

windows_bss relinks an image with 64 MiB of .bss, checks the section table
and the mapped image, and on Windows runs the executable, which reads the
last word of the .bss.
2026-10-10 21:23:19 +13:00
Hannah Lyons 0e03ad0f95 fix(relinker): skip repeated DT_NEEDED libraries 2026-10-10 21:23:19 +13:00
Patrick Elsasser bc444a675d fix(relinker): reject guest modules in SELF containers
A bundled module whose file starts with a SELF container magic
(4f 15 3d 1d or 54 14 f5 ee) was skipped like any other non-ELF file,
so the relink succeeded without it and the module was missing at run
time. The guest module scan now throws, naming the module, as
ElfReader already does for a SELF executable.

Fixes #2599

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:22:58 +02:00
Dean Galvin ec2bb21e70 fix(savedata): export sceSaveDataCancel
Palworld (PPSA23126) imports sceSaveDataCancel (e6y3WMBYbiM) from
libSceSaveData and fails to load because no library exports it. Its
signature is unknown, so it is exported without an implementation and
throws if it is called, like sceSaveDataConvert.
2026-10-10 21:22:48 +13:00
AlxcBTW f752ef4f2b fix(agc): defer registered compute shaders without specials to dispatch
A registered compute shader takes its wave size from its header's
specials (dispatch_modifier), and PrepareRegistered read them without a
null check. ps5-opengl registers compute headers without specials, since
it writes the specials pointer only for linked graphics stages, and
passes the wave size in the dispatch initiator instead. Registration
then threw "shader metadata is outside the registered header".

Such a shader is now deferred like the other shaders that can't be
prepared at registration, so it is prepared at its first dispatch with
the wave size from the initiator's CS_W32_EN.
2026-10-10 21:20:29 +13:00
Doston Abdullayev 5cb7de6ba9 fix(libkernel): return every command-line argument as UTF-8 from getargv on Windows
On Windows, getargc and getargv reported only the executable path, read
with GetModuleFileNameA in the ANSI code page, and dropped every other
argument. Linux returns the whole command line from /proc/self/cmdline,
and the relinker's Windows entry stub already passes the guest entry all
arguments converted to UTF-8.

Parse GetCommandLineW with CommandLineToArgvW and convert each argument
to UTF-8 with WC_ERR_INVALID_CHARS, as the entry stub does, so getargv
matches the entry's argv and the Linux behaviour. The Linux path is
unchanged.
2026-10-10 21:20:29 +13:00
AlxcBTW ce8bee6980 fix(agc): render into one slice of a 2D array color target
DecodeColorTileMode rejected 2D color targets with a nonzero MIP0_DEPTH, so
an array target could only be rendered into through a view of a surface that
declares one slice. radeonsi sets CB_COLOR_ATTRIB3.MIP0_DEPTH to the last layer
of an array target (si_state.c, ac_descriptors.c), and Mesa-built homebrew
emits such targets. The view's slice already moves the target by one slice
size; it is now also checked against MIP0_DEPTH.
2026-10-10 21:20:29 +13:00
AlxcBTW 649782b7b6 fix(libc): export the remaining exception entry points natively on Windows
On Windows libc exports __cxa_init_primary_exception, std::uncaught_exception
and std::uncaught_exceptions only as _nid_postfix symbols (GCC_GLOBAL_ALIAS
is empty there), so host modules bind libstdc++-6.dll's versions:

- std::make_exception_ptr, which std::promise's destructor uses for
  broken_promise, allocated the exception with libc and initialized it with
  libstdc++'s __cxa_init_primary_exception, whose header layout differs.
  A test that makes one and rethrows it dies with an access violation.
- std::uncaught_exceptions read libstdc++'s thread state, which libc's
  throws never touch, so it returned 0 while an exception unwound. The
  AGC driver's deferred-label guard relies on it to tell a failed record
  from a finished one.

The three are now exported natively, like __cxa_throw and the rest.
__cxa_init_primary_exception also sets the reference count to 0, as the
Itanium ABI does: the exception_ptr created next takes the only
reference, so a made exception is destroyed once instead of leaking.
2026-10-10 21:20:29 +13:00
AlxcBTW bc8587a6fe fix(libc): end the process without detach routines in _Exit on Windows
On Windows std::_Exit ends in ExitProcess, which still runs every module's
DLL_PROCESS_DETACH and TLS callbacks after the other threads are gone. A
static destructor that joins a worker then waits forever: a title that calls
_Exit while libSceVideoOut's flip queue runs (ps5-opengl's retirement
fail-stop) stays alive in FlipQueue's destructor. _Exit and libkernel's _exit
now terminate the process with TerminateProcess, as _exit ends a POSIX
process: no atexit handlers, stream flushes or module destructors.
2026-10-10 21:20:29 +13:00
Samuel Jean c62da4004e test(font): isolate guest_font system font lookup 2026-10-10 21:20:29 +13:00
AlxcBTW bf18420007 feat(agc): sample with DISABLE_CUBE_WRAP through non-seamless cube samplers
Guest samplers with DISABLE_CUBE_WRAP (S# word 0 bit 28) are created with
VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT when the device enables
VK_EXT_non_seamless_cube_map; RADV maps the flag to the same bit. The bit
only changes cube filtering, so without the extension the sampler is still
created and only a cube texture sampled through it throws.
2026-10-10 21:20:28 +13:00
alfalfa-star 3bb4494ea7 perf(agc): size the device staging pool from the device-local heap
The buffer pool's device tier (detiler scratch buffers and the staging
shadows of written guest buffers) retained at most 512 MiB by default.
A title whose working set of these buffers is larger allocates and
frees device memory continually: PPSA14632 (LEGO Horizon Adventures)
had 70761 misses and 69828 evictions per 10 s with 485 of 512 MiB
retained, each a vkAllocateMemory or vkFreeMemory.

The default budget is now an eighth of the largest device-local heap,
and at least the old 512 MiB, so a 16 GiB card retains up to 2 GiB and
an 8 GiB card 1 GiB. APS5_STAGING_POOL_MIB still sets it.

Only the constructor knows the device, so only the budget comes from the
heap. Whether the tier is in use at all (APS5_STAGING_POOL_MIB unset or
not 0) stays a static check, DeviceTierEnabled, which Capacity, Usage and
tierFor share, so the size classes and the tier stay consistent.

On PPSA14632 with 2 GiB the device tier has 1312 misses and 99
evictions per 10 s (1628 MiB retained), and presents rise from about 34
to about 39 per 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:19:34 +02:00
Adrià f6af6d11d3
Merge pull request #2123 from LuisBiceps/feat/libkernel-waitpid-no-children
feat(libkernel): report no child processes from waitpid
2026-10-10 10:18:56 +02:00
Scott Schuster c160d31649 feat(agc): accept the LINE_STIPPLE_TEX and POS_FIXED_PT pixel inputs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:18:16 +02:00
Adrià 7c33f29c69
Merge pull request #2085 from orbz22/fix/agc-denormal-clear-colors
perf(agc): fill-clear small-float denormal patterns on devices whose clears keep them
2026-10-10 10:16:09 +02:00
Morten Holm 93b0f48d37 fix(shader): keep s_cselect_b64 of two masks as a lane bit and fold constant masks
A select of exec and zero gives a mask that is the same for every lane. Reading
it back went through a lane number, which Metal does not have in a vertex
shader, so MoltenVK rejected the shader. The select now stores the lane bit and
marks the pair as a mask, a constant mask word reads as a constant, and the
constant folder removes the bit test on an all-zero or all-one word.

agc_scalar_select_mask runs the translated IR over a wave and pins the lane
values for scc set and clear, a source that differs per lane, the two wave64
halves differing, a destination that is also a source, and constant and
literal sources.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 10:15:05 +02:00
Adrià ddcb251a97
Merge pull request #2092 from authurtabo-byte/fix/agc-color-compare-forms
fix(agc): accept additional color comparison image forms
2026-10-10 10:13:30 +02:00
Adrià 4eff3bc293
Merge pull request #1913 from gunerky/codex/tls-test-groups
test(relinker): split TLS coverage into bounded CTest groups
2026-10-10 10:13:07 +02:00
Adrià eab888e02f
Merge pull request #2573 from oneandonlydean/fix/carry-2241
fix(agc): zero-fill a vertex fetch past the record count
2026-10-10 10:13:05 +02:00
Adrià 3539d1ce0b
Merge pull request #1959 from Raghav314/fix/recompiler-formatted-buffer-once
fix(recompiler): emit a formatted buffer access through one function per resource
2026-10-10 10:11:19 +02:00
Adrià Franch 8de5e70477 docs(technicaldebt): shorten the waitpid entry
Requested by @oneandonlydean in review.
2026-10-10 10:11:04 +02:00
LuisBiceps c059cc733f refactor(libkernel): move waitpid and its TechnicalDebt entry away from lines open pull requests change
waitpid now sits between exit and _exit, and its TechnicalDebt entry follows the packed horizontal gathers entry, so the open system and getuid pull requests and the thread cancellation test pull request no longer touch the same lines.
2026-10-10 10:11:04 +02:00
LuisBiceps ac6852ec26 test(libkernel): check every waitpid option set on every pid, with and without a status
Unknown options are now checked for every pid, with 0x80 and 0x80000040 added, and so are valid combinations such as WNOHANG | WUNTRACED. Each call is repeated with a null status. The TechnicalDebt entry cites kern_wait, which adds WEXITED and WTRAPPED, and lists pdfork.
2026-10-10 10:11:04 +02:00
LuisBiceps 918bc0a49c feat(libkernel): report no child processes from waitpid
waitpid returns -1 with ECHILD, or EINVAL for an option FreeBSD does not know, and leaves the status unwritten: AnyPS5 runs the title as one process and exports nothing that creates a child. VLC PPSA85300 stops on main at this import.
2026-10-10 10:11:04 +02:00
Raihan Abdul Majid bafca2ffda perf(agc): fill-clear small-float denormal patterns on devices whose clears keep them
FillClearColor refused half and B10G11R11 patterns with a denormal code,
since an implementation may flush them in a clear, so such fills over a
resident image took the CPU path: PPSA01325 fast-clears its 3840x2160
R16G16_SFLOAT target 0x515390000 with a denormal half every frame, a
33 MiB guest write and re-upload (about 85 ms).

ClearKeepsDenormals probes the device once per format: a 1x1 image
cleared with denormal codes (half 0x0001, 0x83ff, 0x0200, 0x8001;
11/10-bit 0x001) and read back. When the bits survive, FillClear takes
the refused pattern again with SmallFloat decoding denormals exactly.
NaNs, float32 denormals and the SNORM minimum stay refused.

agc_driver_recorder_tests clears an R16G16_SFLOAT resident image with a
normal, a denormal and a NaN pattern: the denormal is cleared exactly
when the probe says the device keeps it, and the NaN is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
2026-10-10 10:10:51 +02:00
Alex Collini 381d5b37b7 fix(recompiler): hold 64 images in a sampled image heap
A shader reported in review binds 40 sampled images of one class, more
than 32. The cap only bounds the compact heap arrays, so no layout or
ABI version changes. The test covers 40 images and a full class through
the constant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:09:43 +02:00
Alex Collini ea22c8286d fix(recompiler): hold 32 images in a sampled image heap
A compute program of PPSA26344 binds 29 sampled images of one class, more
than the 16 a typed sampled heap held, and failed with "shader image heap
capacity exceeded". Heap arrays are declared with their compact length,
so shaders that fitted before keep their layout and SPIR-V.

Bindless image tables keep 16 slots: they were sized by the same constant,
and each slot costs an image entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:09:42 +02:00
Adrià faf6a11701
Merge pull request #1917 from TheAggie/feat/agc-radv-gfx10-packets
feat(agc): accept the GFX10 packet forms RADV emits
2026-10-10 10:09:36 +02:00
MiniRML 97dfbfe4e0 test(videoout): make SDL video driver configurable 2026-10-10 01:08:19 -07:00
authurtabo-byte af635e22eb build(agc): include RDNA decoder headers
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-10 01:08:04 -07:00
authurtabo-byte 42bc9426d3 test(agc): correct bilinear comparison reference
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-10 01:08:04 -07:00
authurtabo-byte a76b0dc461 fix(agc): reject unsupported color comparison forms
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-10 01:08:04 -07:00
authurtabo-byte e50bd2f824 fix(agc): retain anisotropic compare rejection and test sRGB forms 2026-10-10 01:08:03 -07:00
authurtabo-byte f7ca33cb9d fix(agc): accept additional color comparison image forms 2026-10-10 01:08:03 -07:00
gunerky 6767bc7a35 docs(relinker): keep test investigation in PR description 2026-10-10 10:07:33 +02:00
gunerky 047a25820a docs(relinker): record unresolved TLS test delays 2026-10-10 10:07:33 +02:00
gunerky b2ff4f4b02 test(relinker): split TLS coverage into bounded CTest groups 2026-10-10 10:07:33 +02:00
Adrià 2c4828a63d
Merge pull request #2072 from STUPIDCONTEM/fix/srt-signed-comparison
fix(shader): evaluate signed comparisons in SRT expressions
2026-10-10 10:07:30 +02:00
Adrià 5560b54d69
Merge pull request #2071 from STUPIDCONTEM/fix/linked-shader-stage-abi
fix(agc): prepare combined shader layouts when linking
2026-10-10 10:06:56 +02:00
Adrià d185c31678
Merge pull request #2348 from Pipodi/fix/1d-storage-through-2d-stores
fix(shader): write 1D storage images through 2D image stores
2026-10-10 10:06:36 +02:00
Dean ac75a96dd7
Merge pull request #1908 from TheAggie/fix/libkernel-sched-other-priority
fix(libkernel): accept SCHED_OTHER in sched_get_priority_max/min
2026-10-10 21:05:56 +13:00
Dean 4faa14ef6a
Merge pull request #1783 from babyhuey/feat/libc-wide-ctype
feat(libc): implement the C locale wide character class functions
2026-10-10 21:05:48 +13:00
Dean 64c13bc98d
Merge pull request #2032 from Aryansh1520/fix/audioout2-drop-haptics-without-pad
fix(audioout): drop vibration ports when no pad audio device is open
2026-10-10 21:05:41 +13:00
Adrià 89a1fb4ea8
Merge pull request #2190 from obojeoboje/fix/test-registration-command-only
fix(tools): ignore test names when checking executable registration
2026-10-10 10:02:58 +02:00
Adrià 0bc8313a25
Merge pull request #2177 from MarcZX100/codex/fix-color-compare-negative-wrap
fix(shader): normalize negative color comparison wrap indices
2026-10-10 10:02:56 +02:00
Adrià 933b3ca5b1
Merge pull request #2595 from oneandonlydean/revert/1629
revert(agc): undo #1629's sceAgcDcbResetQueue packet sequence
2026-10-10 10:02:22 +02:00
Adrià d4b5cd6131
Merge pull request #2230 from QRMOE/fix/libkernel-pthread-rename-limit
fix(libkernel): reject overlong POSIX thread names
2026-10-10 10:01:28 +02:00
Adrià 700d5a64c8
Merge pull request #2312 from SleglJan/feat/shader-lds-float-atomics
fix(shader): LDS float atomics quiet signalling NaNs and flush denormals as the hardware does
2026-10-10 10:00:51 +02:00
Adrià af1a8edfe1
Merge pull request #2583 from gjonn/perf/async-registration-prepare
perf(agc): prepare registered shaders in the background
2026-10-10 10:00:11 +02:00
Adrià 034dd75f85
Merge pull request #2204 from XairRrR/feat/videoout-deferred-flip-buffer
feat(libs): resolve command-buffer flip buffers when the GPU reaches the flip
2026-10-10 09:59:35 +02:00
danzaio 5e3268969b fix(agc): zero-fill a vertex fetch past the record count
A strided vertex fetch whose index is at or past the descriptor's num_records threw and aborted the title. PPSA01325 draws its fullscreen composite as a 4-vertex strip over a 3-record buffer, so the fourth vertex past the records stopped presentation.

Hardware returns (0, 0, 0, 0) for such a fetch with OOB_SELECT 0 and 1, measured on RDNA2 gfx1036 with tools/hw-oracle in #2241. VertexBufferReadSize now spans the whole fetch, and the staging copy reads the record bytes then zero-fills from num_records * stride onward. Each such fetch gets its own copy, outside the shared copies of its sibling attributes, the host-import in-place path and the draw-snapshot cache. OOB_SELECT 2 and 3 keep throwing past num_records, since each needs its own rule. Recorded in docs/dev/TechnicalDebt.md.
2026-10-10 20:58:25 +13:00
EdouardSence 94409c9f32 fix(libkernel): keep the thread id 64-bit on every host
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:58:05 +02:00
EdouardSence 9ba1b06a4e fix(libkernel): start the pthread object with the thread id
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:58:05 +02:00
Adrià Franch f6d97ad3d2 test(agc): drop the 1D-T# image_load refusal that main now accepts
eb06284c7 made a read-only 2D image_load through a 1D T# valid, so the
test no longer pins a refusal. The TechnicalDebt line now says storage
loads still throw.
2026-10-10 09:57:16 +02:00
Dean Galvin ea62569836 revert(agc): undo #1629's sceAgcDcbResetQueue packet sequence
#1629 makes sceAgcDcbResetQueue throw 'unsupported op bit 0x40' (and for
0x200/0x400). Dreaming Sarah and Astro Bot call it with op bit 0x40 at
start-up, so both abort before the first frame. Main with only #1629
reverted runs Dreaming Sarah normally again (59.9/59.9 fps, no skipped
draws, no flashes).
2026-10-10 20:57:15 +13:00
Adrià Franch c77a6f14f3 fix(shader): keep both image mode blocks after rebase 2026-10-10 09:55:37 +02:00
Alex Collini 6c4660b73c fix(shader): ignore y in 2D stores through a 1D storage image
Measured on RDNA2 (gfx1035) in review: image_store with DIM 2D through a
1D T# writes texel x for every y, including y = 0xffffffff. The T# type
decides the addressing and DIM only how many address VGPRs are read. The
store no longer drops y != 0.

The test now pins the second store at y = 1 with dmask 0x5: texel x holds
its components 0 and 2, components 1 and 3 are 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:55:37 +02:00
Alex Collini 14d9b13cd8 fix(shader): write 1D storage images through 2D image stores
A compute program of PPSA26344 writes a 1D storage image with image_store
DIM 2D, and no runtime image mode matched its T#. A write-only 2D storage
access now also gets a 1D mode. A store through it is dropped when y is not
0, as a one-texel-high image bounds it; this mirrors the measured 3D loads
through 2D T#s of #2023 and is listed in TechnicalDebt as unmeasured.

Loads, atomics and image_store_mip through such a pair still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:55:37 +02:00
Привалов Александр Владимирович e419096bff fix(tools): ignore test names when checking executable registration 2026-10-10 09:54:44 +02:00
XairRrR c9fe124c10 feat(libs): resolve command-buffer flip buffers when the GPU reaches the flip
A flip packet names a buffer index; the buffer was looked up when the
command buffer was submitted, so a title that registers its buffers
after submitting the first frame failed with "flip buffer is not
registered". The buffer is now resolved when the GPU reaches the flip,
as the hardware does. A flip whose buffer is still unregistered then
presents black and completes (see TechnicalDebt).

Uncharted: Legacy of Thieves Collection (PPSA05684) submits its first flip before registering its buffers and stopped with "flip buffer is not registered".
2026-10-10 09:54:29 +02:00
Adrià a29bae31af
Merge pull request #2572 from oneandonlydean/fix/carry-2237
fix(shader): read 2D image accesses through 1D T#s as measured
2026-10-10 09:54:13 +02:00
QRMOE b8f04c6773 build(libkernel): register thread-name regression
AI-assisted: yes. Final code passed the complete Windows build, eight focused runtime tests and four deliberate-fault checks.
2026-10-10 09:54:11 +02:00
QRMOE 022e6be86a fix(libkernel): reject overlong POSIX thread names
AI-assisted: yes. Match the firmware 13.60 probe in PR #1798: names of 32 bytes or more return guest ENAMETOOLONG=63 and preserve the prior name. The complete final change passed a full Windows build and eight focused runtime tests.
2026-10-10 09:53:55 +02:00
QRMOE 872775c703 test(libkernel): cover POSIX thread-name limits
AI-assisted: yes. Validated with the final library change on Windows; full build and eight focused runtime tests pass. Expected rename behavior comes from the public firmware 13.60 probe in PR #1798.
2026-10-10 09:53:54 +02:00
Adrià Franch ac03a5b718 docs(architecture): describe background shader preparation at registration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 09:52:20 +02:00
Gjon Gojcevic 6db5c13696 perf(agc): prepare registered shaders in the background 2026-10-10 09:52:20 +02:00
Adrià 2944cc3266
Merge pull request #2304 from HamidRezaLS/perf/relinker-cfg-zero-copy
perf(relinker): single-pass CFG instruction decoding and zero-copy text span
2026-10-10 09:51:58 +02:00
Adrià a828da9c53
Merge pull request #2305 from TheAggie/perf/shader-wide-bda-stores
perf(shader): store multi-dword global writes with one BDA lookup
2026-10-10 09:51:20 +02:00
Adrià d697af329d
Merge pull request #2351 from Faffu/fix/avplayer-nosync-late-frames
fix(avplayer): skip late video frames in no-sync mode while audio drives the clock
2026-10-10 09:50:52 +02:00
Adrià ada939d2eb
Merge pull request #2035 from CouchRiv/fix-shader-f64-snan-ieee0
fix(shader): quiet f64 signaling NaNs only in IEEE mode
2026-10-10 09:49:38 +02:00
Hamidreza 41856ea6c5 perf(relinker): single-pass CFG instruction decoding and zero-copy text span 2026-10-10 09:48:02 +02:00
Adrià f70a091f90
Merge pull request #2380 from SleglJan/fix/shader-trig-quarter-fold
fix(shader): make v_sin and v_cos linear within 2^-12 of a turn from a zero
2026-10-10 09:47:14 +02:00
Adrià 382fe47c2d
Merge pull request #2081 from orbz22/perf/agc-dword-pattern-fill
perf(agc): handle the dword pattern-fill kernel as a buffer fill
2026-10-10 09:46:38 +02:00
Adrià 08729e07fd
Merge pull request #2025 from snoozedDev/feat/shader-fp16-overflow
feat(shader): follow FP16_OVFL in every f16 result
2026-10-10 09:44:36 +02:00
Adrià 4220bf846e
Merge pull request #2575 from oneandonlydean/fix/carry-2352
fix(agc): retire host imports before guest unmap
2026-10-10 09:44:26 +02:00
Faffu 068da6a99f fix(avplayer): skip late video frames in no-sync mode while audio drives the clock
In SCE_AVPLAYER_AV_SYNC_MODE_NONE every decoded frame was handed out in
order, so a title that requests video slower than the film's frame rate
fell behind its audio (about 52 s by the end of the PPSA12544 intro).
While the title pulls audio, frames the audio clock has already passed are
now skipped; frames that are not late are handed out as before.

Fixes #1635

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:42:20 +02:00
Jan Šlégl 4fb613ec40 fix(shader): flush LDS float atomic inputs for FP_DENORM_FLUSH_IN as well
On RDNA2 (gfx1036) ds_min/max/cmpst(_rtn)_f32 and _f64 flush both operands
when bit 0 of the type's denormal field is clear: field 2 flushes like field
0, field 1 keeps like field 3, in IEEE 0 and 1. The flush decision now tests
that bit. agc_driver_lds_float_atomic_modes adds FLOAT_MODE 0x50 (both fields
1) and 0xa0 (both fields 2), and the TechnicalDebt entry records the measured
fields.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-10 09:40:42 +02:00
Jan Šlégl c2a9491e96 fix(shader): LDS float atomics quiet signalling NaNs and flush denormals as the hardware does
ds_min/max/cmpst_f32 and ds_min/max/cmpst_f64 with their _rtn forms follow the
rule measured on RDNA2 (gfx1036): both operands are flushed to a signed zero
when the type's denormal field flushes, a signalling-NaN data operand is stored
quieted, else a signalling-NaN old value, else a quiet NaN loses, else the
ordered compare decides, and the flushed value is written. The shared f32
path used the host's float compares, so its NaN and denormal results were the
driver's; the shared f64 path lacked the signalling-NaN rules the buffer path
has. Both now use AtomicFloatBits. The translation marks the shared float
atomics with the mode's flush in MemoryInfo.

The new agc_driver_lds_float_atomic_modes pins 32 operand pairs per type in
the titles' mode, with both fields kept and with both flushed. The 64-bit
test's model gets the signalling-NaN rule and one lane kind now feeds the
signalling NaN of its table into min/max.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-10 09:40:41 +02:00
Alex d199fbc708 fix(shader): quiet f64 signaling NaNs only in IEEE mode
The f64 unary instructions, v_ldexp_f64, v_div_fixup_f64 and
v_cvt_f64_f32 always quieted a signaling NaN. The hardware does that
only with IEEE_MODE=1, as #1867 measured for the f32 and f16 forms;
with IEEE=0 the NaN comes out unchanged, measured on gfx1036.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 09:40:09 +02:00
Adrià Franch 64193dd96d docs(technical-debt): measured v_sin and v_cos error inside the bands
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 09:39:14 +02:00
Jan Šlégl 1f1539b957 fix(agc): accept 2 ULP at the cosine's maximum in agc_driver_sin_cos_near_zero
The ±6.1e-5 lanes take the driver's cosine of a tiny angle, where RADV
returns the hardware's 0x3f7ffffe, NVIDIA 0x3f7ffffd and Intel ANV
0x3f800000 (reported by Kikoarl on #2380), so the lanes tolerate 2 ULP
instead of 1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-10 09:39:02 +02:00
Jan Šlégl 909281c994 fix(shader): make v_sin and v_cos linear within 2^-12 of a turn from a zero
After #1979 the cycle is exact, but the driver's sine of the radians loses
tiny results to its absolute error, and near the zeros of sine at k + 0.5
and of cosine at k ± 0.25 the f32 radians drop the low bits of the cycle.
Measured on RDNA2 (gfx1036), the hardware returns the input times 6.2831826
for every input below 2^-12 of a turn and stays within 7 ULP of the f32 2π
times the distance at the half and quarter turns.

Within 2^-12 of a turn from a zero the lowering now returns the linear term
of the exact distance to that zero, with the hardware's constant at the
integers and the f32 2π elsewhere; everywhere else it keeps the driver's
sine or cosine of the radians. agc_driver_sin_cos_near_zero pins 32 inputs
per type from the oracle with per-lane tolerances.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-10 09:39:01 +02:00
Adrià 4e9d298eac
Merge pull request #2521 from Celegans12/perf/shader-sorted-dominance-sets
perf(recompiler): preserve sorted dominance sets during insertion
2026-10-10 09:36:31 +02:00
Adrià Franch 6e9d0e3fbb test(agc): register the host import unmap test in ctest 2026-10-10 09:35:43 +02:00
Dean Galvin 95a2d1184a fix(agc): load the import destroy functions when the device is unchanged
A context without a device, such as the graphics test's mock, leaves state.device equal to context.device, so refreshImports never loaded destroyBuffer and freeMemory and retiring an import called a null pointer.
2026-10-10 09:35:43 +02:00
MarcZX100 cf5c3ebef3 fix(agc): retire host imports before guest unmap
The pin waiter now receives the mutation range, drains GPU work and retires every overlapping host import before the unmap callback releases the pages. Deferred import retirement keeps only the device handle and the Vulkan destroy functions, so the static import registry no longer owns a Context or its BufferPool past the device.
2026-10-10 09:35:43 +02:00
Adrià Franch 89a115283d fix(shader): update the ImageResource size check for flatLineCompatible
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 09:35:34 +02:00
Nahuel Genchi eb06284c78 fix(shader): read 2D image accesses through 1D T#s as measured
A compute shader in Astro Bot samples an image as 2D while the bound
T# is 1D, and the recompiler refused it. Offer a 1D runtime mode for
sampled images used only by image_sample_lz and mip-less image_load,
which reads the texel the first coordinate selects, as measured on
RDNA2 in #2237.
2026-10-10 09:35:34 +02:00
Adrià 2f655b124a
Merge pull request #2327 from EdouardSence/perf/agc-registration-structurize
perf(agc): drop the redundant structurize pre-check at registration
2026-10-10 09:34:36 +02:00
eliasbruno124-dev 5a1b5bf947 fix(libSceAgcDriver): report unavailable bulk resource registration 2026-10-10 09:34:26 +02:00
ale 0bea402a1c feat(shader): follow FP16_OVFL in every f16 result
With FP16_OVFL=1 the hardware writes an f16 result that would round to
infinity as the largest finite value of that sign, unless a source
operand is infinite. v_div_fixup_f16 keeps the infinity it writes for a
zero denominator or an infinite numerator. Measured on RDNA2 (gfx1036)
at IEEE=0 and IEEE=1 with f16 denormals kept and flushed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 04:32:38 -03:00
Adrià 17d69d173f
Merge pull request #1902 from fisherjoey/fix/agc-null-pixel-on-demand
fix(agc): prepare the null pixel program at draw when its variant was not prepared
2026-10-10 09:32:29 +02:00
Raihan Abdul Majid 26035fab57 perf(agc): handle the dword pattern-fill kernel as a buffer fill
A 64-thread compute kernel (69 dwords) stores pattern[min(i % s9, 3)],
the pattern in s4..s7, to dword i of a 4-byte-stride buffer for every
i below min(launched threads, s8, num_records), with the group id in s10.
PPSA01325 runs it every frame to clear DCC keys, HTILE and other
metadata. It ran as a shader; a direct dispatch with a period of 1, 2
or 4 dwords, whole 16-byte units and a 16-byte aligned destination now
goes through fillBuffer like the existing fill kernel (clear path,
FillBuffer, key memo). APS5_NO_FILL_HLE turns both off.

tests/execution/DwordPatternFill.cpp checks the matcher and runs the
kernel through Submit for matched and unmatched cases (periods 3 and 5,
partial counts, record clamps, a partial dispatch); with
APS5_NO_FILL_HLE=1 the same expectations hold for the translated kernel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
2026-10-10 09:31:03 +02:00
Adrià e8b47b9270
Merge pull request #2043 from CouchRiv/fix-shader-cube-sc-tc-snan
fix(shader): quiet signaling NaN cube results in IEEE mode
2026-10-10 09:28:56 +02:00
Adrià f198c8ff97
Merge pull request #2036 from CouchRiv/fix-shader-minmax-f16-f64-ieee
feat(shader): follow IEEE_MODE in f16 and f64 min and max
2026-10-10 09:28:37 +02:00
Adrià 51b8cef4f9
Merge pull request #1969 from lubaxe/fix/agc-null-vertex-buffer-descriptor
fix(agc): read zero for vertex attributes behind a null V#
2026-10-10 09:28:06 +02:00
Adrià 41e34915b8
Merge pull request #1777 from MathiasDevelopes/feat/libkernel-random-device
feat(libkernel): open /dev/random and /dev/urandom for reading
2026-10-10 09:27:46 +02:00
Adrià d99babe24c
Merge pull request #1607 from saarthakpant/fix/agc-per-stage-color-attachments
fix(agc): count a pixel stage's colour attachments against maxPerStageResources
2026-10-10 09:25:20 +02:00
MarcZX100 9ffd06eab0 docs(shader): identify llvmpipe wrap regression version 2026-10-10 07:24:07 +00:00
EdouardSence d8ae88cf54 perf(agc): drop the redundant structurize pre-check at registration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:23:55 +02:00
MarcZX100 606bc161aa test(agc): cover negative point-wrap offsets 2026-10-10 07:23:24 +00:00
MarcZX100 15673a94ea docs(shader): record unverified color compare wrap 2026-10-10 07:23:24 +00:00
MarcZX100 7bd8a0a66a fix(shader): normalize negative color compare wrap indices 2026-10-10 07:23:24 +00:00
Adrià 5fd101099d
Merge pull request #1733 from TheAggie/feat/agc-texture-bc-swizzle
feat(agc): accept texture BC swizzles that leave the sampled border unchanged
2026-10-10 09:23:13 +02:00
Dean 256b8ed4f3
Merge pull request #2584 from oneandonlydean/revert/2279
revert(shader): undo #2279's fma NaN result selection
2026-10-10 20:22:49 +13:00
Adrià b23bd7323f
Merge pull request #1831 from yabanana/fix/macos-descriptor-array-ranges
fix(agc): preserve descriptor array ranges in draw snapshots
2026-10-10 09:22:08 +02:00
Adrià 5596e5bd62
Merge pull request #1837 from EdouardSence/fix/agc-shader-header-copies
fix(agc): accept bound copies of a registered shader header that differ only in user_data
2026-10-10 09:20:19 +02:00
Celegans12 f6fbb480c5 perf(recompiler): preserve sorted dominance sets during insertion
Both dominance analyses start from sorted unique sets and intersect them.
Insert the current block ID with lower_bound instead of sorting again.
Preserve every intermediate set and the existing ID-order iteration.
Keep the generic unsorted helper and all graph rewrite logic unchanged.
Compare both analyses against the original algorithms on six raw CFGs.
Cover finite loops, closed SCCs, unreachable islands and permuted IDs.
2026-10-10 09:20:14 +02:00
Adrià 2f250f83aa
Merge pull request #1815 from eliasbruno124-dev/fix/nested-required-modules-publication
fix(relinker): discover required modules in nested standard directories
2026-10-10 09:19:07 +02:00
Adrià eba8525acb
Merge pull request #1924 from fisherjoey/fix/depth-bias-per-face
fix(agc): draw each face with its own depth bias
2026-10-10 09:19:03 +02:00
Hannah Lyons 1bfb3cbf09 feat(libc): implement the C locale wide character class functions 2026-10-10 03:18:53 -04:00
Adrià 3d48f65ae1
Merge pull request #1862 from aashishaxo/fix/issue-1581
fix(libSceAgcDriver): step over the one-dword NOP pad ffff1000
2026-10-10 09:18:40 +02:00
Sasha Papo f1c15c2cda docs: record the null vertex buffer V# as not measured on hardware
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:17:49 +02:00
Sasha Papo e6e0b69101 fix(agc): read zero for vertex attributes behind a null V#
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:17:49 +02:00
Aryan Sharma e548e594fa test(audioout): check pad ports in the main mix without a pad device
With SDL's disk driver no pad audio device is open, so AudioOut2MixPorts
runs with no pad output. A vibration port and a mono pad speaker port
are pushed together: only the speaker's data reaches the main mix, and
a vibration port alone leaves it silent.
2026-10-10 12:46:54 +05:30
Aryan Sharma 34d09b5460 fix(audioout): drop vibration ports when no pad audio device is open
Without a DualSense audio device every AudioOut2 port was mixed into the
main output, including PAD_VIBRATION ports. Their waveforms drive the
controller's actuators on the console and are never heard; mixed into
the speakers they made PPSA28997's combat about 20 dB louder than its
dialogue. Vibration ports are now left out in that case; pad speaker
ports still go to the main output.
2026-10-10 12:46:54 +05:30
Adrià f9cd694c32
Merge pull request #1988 from NevesHenry/fix/libkernel-linux-thread-stack-size
fix(libkernel): give Linux guest threads the stack size they request
2026-10-10 09:16:35 +02:00
Alex 6d1fe2b499 feat(shader): follow IEEE_MODE in f16 and f64 min and max
The f16 min/max/min3/max3/med3 now pick NaN results on the bits and
quiet a signaling NaN only with IEEE=1. With IEEE=0, v_min_f64 and
v_max_f64 return the other operand for a NaN, not a quieted NaN. This
completes #1826 for these forms, as measured on RDNA2 (gfx1036).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 09:16:09 +02:00
Adrià Franch b49ffef75a docs(technical-debt): record the /dev/random and /dev/urandom emulation 2026-10-10 09:13:07 +02:00
Adrià 97b985f157
Merge pull request #2046 from CouchRiv/fix-shader-mullit-flush
fix(shader): flush v_mullit_f32 denormals in the float modes that flush them
2026-10-10 09:13:07 +02:00
Adrià Franch aee2d25655 docs(debt): v_cubema no longer left to the driver
Its signaling NaN result is quieted with IEEE=1 by the cube sentence above.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 09:13:06 +02:00
Alex 2185d82522 fix(shader): quiet signaling NaN cube results in IEEE mode
With IEEE_MODE=1 the hardware quiets a signaling NaN that v_cubesc,
v_cubetc or v_cubema_f32 returns, keeping the sign the instruction gives
it; with IEEE=0 the bits pass through. Same rule as #1867, measured on
gfx1036 in both modes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 09:13:00 +02:00
MathiasDevelopes 7810f8464e feat(libkernel): open /dev/random and /dev/urandom for reading
Neither existed under the guest root, so opening them failed and titles
that then read from the descriptor crashed. Opening either for reading
now returns a descriptor whose reads, positioned reads and vector reads
fill the buffer from the host's random device, as
sceRandomGetRandomNumber does. Opening them for writing throws.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 09:12:55 +02:00
Adrià a86ffd3368
Merge pull request #1995 from lubaxe/feat/agc-store-pending-at-flip
feat(agc): store pending storage-image results at each flip with APS5_STORE_AT_FLIP
2026-10-10 09:12:46 +02:00
ah 5f6da63e4a
fix(shader): evaluate signed comparisons in SRT expressions
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPEHi56pUMbT1X4VZwStm9
2026-10-10 02:08:12 -05:00
Dean 01dc5c14a3
Merge pull request #1764 from Zurisen/fix/flock-nonblocking-contention
fix(libkernel): return EWOULDBLOCK from a contended LOCK_NB flock
2026-10-10 20:08:00 +13:00
Dean edbf36ad4c
Merge pull request #2574 from oneandonlydean/fix/carry-2464
fix(relinker): start Windows executables in their own directory
2026-10-10 20:07:53 +13:00
Dean 79d1220320
Merge pull request #2342 from AchrafReyani/fix/remove-readonly
fix(libc): remove read-only files on Windows
2026-10-10 20:07:46 +13:00
Dean 50cea78f6b
Merge pull request #2291 from AchrafReyani/fix/libkernel-null-time-results
fix(libkernel): accept null results in gettimeofday and clock_getres
2026-10-10 20:07:40 +13:00
Daniele Giovane 1730b29c4a fix(agc): preserve descriptor array ranges in draw snapshots 2026-10-10 09:07:26 +02:00
Morten Holm 31b6af028f fix(relinker): leave MH_PIE clear in the macOS executable
The executable is linked at a fixed base with a __PAGEZERO that fills the space below it, and
the guest assumes 16 KB pages. With MH_PIE set dyld slides the image by a multiple of 4 KB,
which breaks that assumption and ends in a SIGBUS (KERN_PROTECTION_FAILURE) in about half of
the launches under Rosetta 2. Clearing the flag keeps the image at its linked address.

test_macos_output.py now reads the header flags and checks that MH_PIE is clear.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 09:07:14 +02:00
Adrià 72ef435ec0
Merge pull request #2143 from erick-dsnk/fix/kernel-aio-completion-errors
fix(kernel): preserve invalid-offset errors in AIO completions
2026-10-10 09:06:53 +02:00
ah 23443fb34d
fix(agc): prepare combined shader layouts when linking
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPEHi56pUMbT1X4VZwStm9
2026-10-10 02:06:51 -05:00
EdouardSence cd1f76c831 fix(agc): accept bound copies of a registered shader header that differ only in user_data
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:06:48 +02:00
Joey Fisher e2664bef83 fix(agc): register the null pixel program with the inputs and user SGPRs its draws use
Since #1178 the SPI_PS_INPUT_ENA/ADDR emplace calls did nothing, so the registered variant had no pixel inputs, and null pixel draws took the last pixel shader's user SGPR count and the bound targets' export mapping. Registration now overwrites those registers, the draw gives the null program no user SGPRs and an empty export mapping, and the at-draw preparation is left for wave32 only. Root cause found by @Raghav314.
2026-10-10 09:06:31 +02:00
Joey Fisher bbfd61430a fix(agc): prepare the null pixel program at draw when its variant was not prepared 2026-10-10 09:06:23 +02:00
Adrià ca412953ea
Merge pull request #2042 from CouchRiv/fix-shader-pack-b32-f16-snan
fix(shader): quiet signaling NaN halves in v_pack_b32_f16 in IEEE mode
2026-10-10 09:05:54 +02:00
Adrià c8e266577a
Merge pull request #1934 from fisherjoey/fix/shader-ancillary-moved-word
fix(shader): carry a packed pixel ancillary through phis when every reader extracts a modelled field
2026-10-10 09:05:48 +02:00
Adrià 04d06f0d45
Merge pull request #2257 from Dextroid17/fix/defer-undecodable-shaders
fix(agc): defer a shader whose code does not decode instead of aborting the title
2026-10-10 09:05:21 +02:00
Joey Fisher e0084a56b0 fix(agc): draw each face with its own depth bias
A draw that rasterizes both faces with different front and back depth
bias was rejected, since Vulkan has one depth bias per draw and the
cull mode is pipeline state. Such a draw is now recorded twice in the
same pass: front faces with the back faces culled and the front bias,
then back faces with the front faces culled and the back bias. A face
whose offset is disabled gets no bias.
2026-10-10 09:04:37 +02:00
Dean Galvin 1be9b1e72f revert(shader): undo #2279's fma NaN result selection
#2279 made agc_driver_f32_arithmetic_nan fail on NVIDIA (Windows):
v_fmamk_f32 returns a quiet NaN where the signalling one is expected
(lane 1 no float mode v_fmamk_f32 is 0x7fc12345, expected 0x7f812345),
5/5 runs on main and 5/5 passing with #2279 reverted. CI's Windows job
skips the AGC execution tests, so it did not show there.

v_fma_legacy was rewritten as a split multiply and add after #2279; it
keeps that and gets back the invalid-product argument it passed before.

Fixes #2581
2026-10-10 20:02:43 +13:00
Adrià 40a5b8fae9
Merge pull request #2142 from MathiasDevelopes/fix/videoout-overlay-bus-flips
fix(libSceVideoOut): overlay-bus flips no longer replace the main output
2026-10-10 09:01:37 +02:00
Adrià 6717a118ca
Merge pull request #2576 from adriadam10/fix/progress-empty-libs
fix(progress): link include-shared libraries and label empty ones
2026-10-10 09:00:44 +02:00
Adrià 3a1c79f387
Merge pull request #2219 from XairRrR/feat/agc-depth-clear-draws
feat(agc-driver): draw DB_RENDER_CONTROL depth clears
2026-10-10 08:59:33 +02:00
Adrià faa889e8f0
Merge pull request #2201 from XairRrR/fix/structurizer-shared-returns
fix(recompiler): clone small return blocks shared by early exits
2026-10-10 08:59:15 +02:00
Adrià Franch f455b42084 test(libkernel): check the Linux host thread handle in pthread start coverage
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 08:57:08 +02:00
Adrià 99b9841ac8
Merge pull request #2033 from TheAggie/fix/libc-fopen-mode
fix(libc): parse fopen and freopen modes as FreeBSD does
2026-10-10 08:57:02 +02:00
NevesHenry faf983ae01 fix(libkernel): give Linux guest threads the stack size they request
scePthreadCreate on Linux started guest threads with std::thread, so every
thread got the host default stack (RLIMIT_STACK, usually 8 MiB) whatever the
title asked for. A thread that asks for more than that and uses it crashes
with SIGSEGV. Once the thread ran, scePthreadAttrGet also reported the host
size instead of the requested one.

Create the thread with pthread_create and a stack of the requested size plus
what glibc keeps at its top (static TLS, the thread control block and the
start_thread frame). That reserve is measured once with a probe thread.
The thread reports [top - reserve - size, top - reserve) as its stack, as
Windows reports [top - size, top), and the creator waits until the range is
set, as on Windows.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:57:00 +02:00
Sasha Papo 3221ae8acd fix(agc): accept only 1 for APS5_STORE_AT_FLIP and test the switch instead of FlushAllPending
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:56:11 +02:00
Sasha Papo ef53b0614f feat(agc): store pending storage-image results at each flip with APS5_STORE_AT_FLIP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:56:02 +02:00
Adrià Franch db491f0c7e docs(technical-debt): record that f32 tininess is detected after rounding on hardware
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 08:55:16 +02:00
Alex b64d413036 fix(shader): flush v_mullit_f32 denormals in the float modes that flush them
With f32 denormals flushed, as in the 0xc0 float mode titles use, the
hardware flushes all three v_mullit_f32 sources and its product like
v_mul_f32, so a positive denormal limit selects -FLT_MAX and a tiny
product gives zero. The recompiler kept denormals in every mode.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:55:16 +02:00
Adrià d5c8e42dfd
Merge pull request #2282 from MathiasDevelopes/fix/recompiler-storage-heap-capacity
fix(recompiler): size a typed storage heap for several images, not one dynamic image
2026-10-10 08:55:15 +02:00
Adrià 40a7711a3e
Merge pull request #2229 from TheAggie/fix/agc-radv-htile-depth-clear
fix(agc): apply RADV's HTILE depth fast clears to the host depth surface
2026-10-10 08:54:11 +02:00
Alex e1f81abd85 fix(shader): quiet signaling NaN halves in v_pack_b32_f16 in IEEE mode
With IEEE_MODE=1 the hardware quiets each signaling NaN half that
v_pack_b32_f16 packs, after neg and abs; with IEEE=0 it copies the bits.
The recompiler always copied them. Same rule as #1867, measured on
gfx1036 in both modes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:52:03 +02:00
Dean 6284b64fa5
Merge pull request #2570 from oneandonlydean/fix/libc-future-result-exception-2540
fix(libc): release future results' exceptions through libc on Windows
2026-10-10 19:51:09 +13:00
Adrià Franch 507f5707dc fix(progress): link include-shared libraries and label empty ones
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 08:49:58 +02:00
Adrià 653e3d04d7
Merge pull request #2097 from treuenten/fix/relinker-entry-stub-rel32
fix(relinker): reject a Linux entry stub whose call cannot reach the entry
2026-10-10 08:49:35 +02:00
Dextroid17 e5b32bb429 fix(agc): defer a shader the decoder does not implement instead of aborting
The registered-shader decode ran before the deferral decision, so a single
instruction the decoder does not implement ended the title at registration
instead of deferring the shader to its first use.

Give the decoder's unsupported-instruction failures their own type
(UnsupportedInstructionError): the five family-scoped SOP opcode defaults and
the MIMG opcode lookup (which now names the opcode) raise it, and the decode in
PrepareRegistered defers the shader with that reason when it hits one. Any
other exception still throws, so the corrupt-code contract is unchanged.

PPSA26344 hits this: unsupported MIMG opcode 229 (0xE5), issue #1941. The
failing word is reproducible offline from the title's own shader store
(cache_ps5/all_shaders.xpps, code word 260), which is how the fixture was
checked before it was written.

Scope: this defers the scalar-family and MIMG opcode gaps. The vector (VOP*)
and memory (SMEM/MUBUF/MTBUF/FLAT/DS) opcode lookups, the modifier-level
"not supported" throws and the malformed/truncated throws still abort.
Widening the deferral to those is a policy call for the maintainers.

Stacked on #1836 (the deferral machinery); re-stacked on its current head so
this diff no longer carries #1836's earlier broad catch. Once #1836 lands only
the decode change remains.

Written with AI assistance.
2026-10-10 08:49:08 +02:00
Adrià Franch 988394447a docs(TechnicalDebt): move the overlay bus line off the end of the section 2026-10-10 08:48:04 +02:00
MathiasDevelopes 85d1eb2e60 fix(libSceVideoOut): overlay-bus flips no longer replace the main output
A title that opens a main and an overlay port flips both, and every flip
was presented as a whole frame, so the window alternated between the two
buses: PPSA01736 shows its intro on the main bus and an empty overlay,
and the intro blinked black on every other frame. Overlay flips now
complete and signal their events without being shown. Compositing the
overlay over the main output is not implemented.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:48:03 +02:00
Dean 6f262eb0f4
Merge pull request #2568 from oneandonlydean/fix/relinker-decode-xop-2559
fix(relinker): decode XOP instructions
2026-10-10 19:47:50 +13:00
Dean 971474b2ac
Merge pull request #2569 from oneandonlydean/fix/f16-native-signed-zero-2483
fix(recompiler): keep the f32 sign on natively converted f16 results
2026-10-10 19:47:41 +13:00
Adrià c20184aba7
Merge pull request #2162 from CouchRiv/fix-shader-fma-mix-f16-fused
fix(shader): round v_fma_mixlo_f16 and v_fma_mixhi_f16 once to f16
2026-10-10 08:46:56 +02:00
Get-fix 975475929e fix(relinker): start Windows executables in their own directory
The guest filesystem root and the save data directory are taken from the
current directory, so an executable started from another directory does
not find its title files and keeps saves elsewhere. Make the executable
directory the current directory in the Windows entry stub before the
system libraries are loaded.
2026-10-10 19:44:06 +13:00
erick-dsnk ace167a578 fix(libkernel): preserve EINVAL in AIO completions 2026-10-10 08:42:19 +02:00
XairRrR 99a96c3df3 fix(recompiler): clone small return blocks shared by early exits
A pixel shader whose early discards branch to one small ending block
gave that block several conditional predecessors outside any loop, and
structurizing failed. When the regular pass throws, the structurizer
restarts from the original graph and first gives each conditional
predecessor its own copy of such a return block (within the clone word
floor and a budget of four clones per block).

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at such a pixel shader with "conditional block 15 has no structured merge".
2026-10-10 08:41:13 +02:00
MathiasDevelopes 83e0a01540 fix(recompiler): size a typed storage heap for several images, not one dynamic image
A typed storage-image heap held four elements, and a dynamic-mip storage
image takes four of them for its mip slots. A shader with a dynamic-mip
storage image and any other storage image of the same class needed five
and failed with "shader image heap capacity exceeded". The mip slots
per dynamic image stay four (StorageMipSlots); a storage heap now holds
sixteen elements (StorageHeapCapacity). Heap arrays are declared with
their compact length, so shaders that fitted before are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 08:40:41 +02:00
Adrià 092e133efe
Merge pull request #2313 from JulioCacko/contrib/shader-preparation-capture
fix(diagnostics): capture failed shader preparation requests
2026-10-10 08:39:37 +02:00
seven 5b9fdd111a fix(agc): count a pixel stage's colour attachments against maxPerStageResources
Vulkan counts the framebuffer colour attachments against maxPerStageResources
for the fragment stage. The draw's attachment count now seeds the fragment
stage's resource total in ShaderResources, so a pixel shader whose buffers and
images fit the limit but whose pipeline exceeds it throws instead of creating
an invalid pipeline. The draw resource cache key carries the attachment count,
so a cached build is never reused by a draw with more attachments.
2026-10-10 12:07:56 +05:30
Adrià b58b1ccff4
Merge pull request #2421 from Pouare514/fix/direct-memory-release-validation
fix(libkernel): reject malformed ranges in sceKernelReleaseDirectMemory
2026-10-10 08:37:29 +02:00
Adrià Franch 1de9bbe7e4 docs(technical-debt): record the HTILE depth fast clear limits
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 08:37:16 +02:00
Scott Schuster ee95202948 fix(agc): apply RADV's HTILE depth fast clears to the host depth surface
RADV clears depth by rewriting HTILE with its clear_htile_mask kernel
(ZMASK to 0) instead of writing depth memory. Recognize that kernel and
clear the matching host depth surface to DB_DEPTH_CLEAR when it is next
bound; the depth target now records its HTILE address.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:36:58 +02:00
Adrià d43d50beb1
Merge pull request #2322 from jweidenh/codex/last-provoking-vertex
feat(agc): support last provoking vertex for native primitives
2026-10-10 08:36:55 +02:00
Adrià d7f24e7652
Merge pull request #2294 from Vabian124/cursor/fix-relinker-reject-non-regular-input-9077
fix(relinker): reject non-regular input files
2026-10-10 08:35:29 +02:00
Alex 3a9da568fe fix(shader): round v_fma_mixlo_f16 and v_fma_mixhi_f16 once to f16
The f16 forms of v_fma_mix computed an f32 FMA and converted it to f16,
so a result that lands on an f16 tie after the f32 rounding was rounded
twice. RDNA2 rounds the exact product-sum once. They now use the exact
f64 path of v_interp_p2_f16 and flush f32 sources like v_fma_mix_f32.
They follow the f16 round and denormal fields on hardware, so another
f16 mode throws, as packed f16 does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:33:43 +02:00
XairRrR 295223f3eb feat(agc-driver): draw DB_RENDER_CONTROL depth clears
DEPTH_CLEAR_ENABLE (DB_RENDER_CONTROL bit 0, Mesa sid.h) makes the DB
write DB_DEPTH_CLEAR wherever the draw covers. Such a draw is now
rasterized as submitted with an always-passing depth write, no depth
bounds, no depth bias and the viewport depth range pinned to the clear
value, so it touches exactly the pixels the title's geometry covers.
Clearing a read-only or absent depth plane throws, at decode and in the
draw precheck. Depth and stencil clears combine; copy, resummarize and
decompress draws still throw.

Uncharted: Legacy of Thieves Collection (PPSA05684) clears with draws
that set DB_RENDER_CONTROL to 0x3 and stopped with "depth/stencil
clear, copy, resummarize or decompress draws (DB_RENDER_CONTROL) is
unsupported (register 0x0 = 0x00000003)".
2026-10-10 08:33:04 +02:00
Adrià 8f693fc82c
Merge pull request #2274 from jweidenh/codex/fix-linux-program-header-count
fix(relinker): count all synthetic Linux program headers
2026-10-10 08:32:53 +02:00
Adrià 9db3480a65
Merge pull request #2330 from simonbbby/fix/relinker-init-array-roots
fix(relinker): collect init and fini array roots through the containing load segment
2026-10-10 08:31:38 +02:00
Julio Cacko 097aaa698b fix(diagnostics): capture failed shader preparation requests 2026-10-10 08:31:22 +02:00
Adrià 55a631bb4a
Merge pull request #1281 from SirDarky/fix/shader-mad-legacy-rounded-product
fix(shader): round the v_mad_legacy_f32 product before the add
2026-10-10 08:31:19 +02:00
AlxcBTW cc56748646 fix(libc): release future results' exceptions through libc on Windows
libc implements the C++ exception runtime and already defines
exception_ptr's out-of-line members, so host modules that link libc
reference-count libc's exceptions. Code inside libstdc++-6.dll does not
see those definitions on Windows: std::__future_base::_Result_base's
destructor is one of them, and it releases the stored exception with
libstdc++'s own exception_ptr::_M_release. That decrements a count 0xa0
bytes before the object, while libc keeps it 0x80 bytes before, so the
decrement lands in the heap memory in front of libc's allocation and
the exception is never freed.

VideoOutDriver reports the presentation thread's start-up failure
through a std::promise, so video_out_flip_lifetime sometimes ended with
0xc0000374 when SDL's offscreen driver refused the window.

libc now defines the base destructor, with a _nid_postfix twin so that
the NID-patched libc keeps its name, and modules bind it there.
2026-10-10 19:29:19 +13:00
MathiasDevelopes c9aae5b5eb fix(recompiler): keep the f32 sign on natively converted f16 results
AMD's Windows driver advertises shaderSignedZeroInfNanPreserveFloat16,
yet OpFConvert from f32 to f16 returns +0 for -0 inputs and for negative
values that round to zero, so six f16 execution tests fail there since
the native conversion was added. Conversion never changes the sign, so
the native path now takes the sign bit from the f32 source, as the
emulated path already does.

Fixes #2483
2026-10-10 19:29:17 +13:00
Dean 2e197741c8
Merge pull request #2208 from AchrafReyani/feat/libc-inet-ntoa
feat(libc): implement __inet_ntoa
2026-10-10 19:28:39 +13:00
Adrià 0aaadd6457
Merge pull request #1599 from andrey231/fix/storage-keep-baseline
fix(agc): store GPU results over CPU-stamped bytes the CPU left unchanged
2026-10-10 08:28:10 +02:00
Adrià 7d94990371
Merge pull request #2300 from AchrafReyani/fix/libkernel-stat-trailing-slash
fix(libkernel): report ENOTDIR from stat for a file with a trailing slash
2026-10-10 08:27:27 +02:00
Achraf Reyani ce8dbc977f fix(relinker): decode XOP instructions
The x86 decoder had no XOP (AMD 8F escape) support and read 8F E8.. as
POP r/m, losing instruction boundaries. Since #2238 roots code addresses
taken by RIP-relative LEA, code analysis reaches CPU-dispatched XOP
paths, such as the vpperm routines in Stremio Plus (PPSA74126), OpenNOW
(PPSA99082) and PPSA99420, and their Windows conversion failed with
"Code analysis: overlapping instruction boundaries". Decode 8F followed
by a map of 8 or more as a three-byte XOP prefix (8F can only be POP r/m
with ModRM.reg 0) with a ModRM operand, an 8-bit immediate in map 8 and
a 32-bit immediate in map 0Ah, in both the length and operand decoders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:27:24 +13:00
Cursor Agent eba1dec764 fix(relinker): reject non-regular input files
A directory opens and tellg reports an enormous size, so the relinker
tried to allocate it and failed with std::bad_alloc. Require a regular
file and a non-negative size before allocating the input buffer.
2026-10-10 08:26:32 +02:00
Adrià 23ed501f4a
Merge pull request #1511 from cubersu/fix/libc-swprintf-wcsrtombs-utf16
fix(libc): format guest wide strings in swprintf as 16-bit units
2026-10-10 08:26:15 +02:00
jweidenh 03cb114779 test(agc): render recompiled guest flat inputs in both vertex modes 2026-10-10 08:26:14 +02:00
jweidenh 3671668472 test(agc): supply pixel registers for provoking vertex precheck 2026-10-10 08:26:14 +02:00
jweidenh 3a8cf3a38b feat(agc): support last provoking vertex for native primitives 2026-10-10 08:26:14 +02:00
Adrià b5315f046d
Merge pull request #2381 from SleglJan/docs/shader-scalar-measurements
docs(shader): record the measured s_call_b64 and null s_swappc_b64 behaviour
2026-10-10 08:25:58 +02:00
simonbbby fcb0b962a7 fix(relinker): collect init and fini array roots through the containing load segment
The unused-filter=1 entry point collector translated DT_INIT_ARRAY and
DT_FINI_ARRAY through PT_DYNAMIC and skipped arrays placed before it, which is
the usual linker layout, so constructors and destructors were not roots and
imports used only by them were dropped. Arrays are now translated through the
PT_LOAD that holds them, slot targets come from RELATIVE relocations when
present, and DT_PREINIT_ARRAY is collected as in the strict filter.
2026-10-10 08:25:50 +02:00
Adrià 1a668689d6
Merge pull request #2133 from queeeef/fix/agc-3d-access-on-2d-texture
fix(shader): bind 2D textures to 3D sample and load accesses as measured
2026-10-10 08:25:22 +02:00
Pouare514 03d975af3c fix(libkernel): reject malformed ranges in sceKernelReleaseDirectMemory
A zero, unaligned, overflowing or out-of-range length reached the physical pool, where a sub-page length silently freed a whole page and fragmented the block map, and an out-of-range length walked the page table past the backing store. Validate alignment and bounds up front and return EINVAL instead.
2026-10-10 08:22:59 +02:00
Adrià 03bf8ff335
Merge pull request #2526 from Celegans12/perf/agc-registration-frontend-pair
perf(agc): reuse frontend within shader registration pairs
2026-10-10 08:20:52 +02:00
Adrià 530b6a4270
Merge pull request #2226 from EdouardSence/fix/agc-conservative-uncertainty-disabled
fix(agc): accept disabled conservative rasterization with uncertainty-region bits
2026-10-10 08:20:08 +02:00
Scott Schuster 75638194b5 feat(agc): accept RADV's compute dispatch and register-load forms
- DISPATCH_DIRECT and DISPATCH_INDIRECT with the SHADER_TYPE header bit,
  which RADV sets on every dispatch, as other packets already may.
- FORCE_START_AT_000 in the dispatch initiator. The driver never offsets
  dispatches by COMPUTE_START_X/Y/Z, so it already starts at zero.
- LOAD_CONTEXT_REG_INDEX, LOAD_SH_REG_INDEX and LOAD_UCONFIG_REG_INDEX in
  their consecutive-register form (a register offset and a count, DATA_FORMAT
  0), which RADV uses to load DB_STENCIL_CLEAR and DB_DEPTH_CLEAR from an
  image's clear values. The offset-and-data form keeps its old checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:20:01 -05:00
Scott Schuster 0e5bd5e5ae feat(agc): accept the GFX10 packets RADV's graphics preamble emits
RADV builds its own command streams. Its preamble and draws use packet
forms the validator refused:

- CONTEXT_CONTROL that only updates the load and shadow enables to zero,
  which RADV emits when it does not shadow registers. It is a no-op.
- SET_UCONFIG_REG_INDEX of VGT_PRIMITIVE_TYPE with index 1, next to the
  index-2 VGT_INDEX_TYPE write already accepted.
- WRITE_DATA to memory (DST_SEL 5) from the graphics queue.
- DMA_DATA with DST_SEL NOWHERE, RADV's L2 prefetch of shader code. It
  writes nothing and resolves to an empty store.
- EVENT_WRITE PIPELINESTAT_START, PIPELINESTAT_STOP, SQ_NON_EVENT and
  VGT_FLUSH. The statistics counters are not modelled, and the events that
  would read them stay rejected.
- ACQUIRE_MEM over the full 48-bit range (COHER_SIZE_HI and COHER_BASE_HI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:20:00 -05:00
Adrià 394b6d049c
Merge pull request #2253 from Raghav314/perf/agc-draw-inputs-in-place
perf(agc): read draw vertex and index buffers in place from host imports
2026-10-10 08:19:00 +02:00
Marcus 5377db48fd fix(shader): round the v_mad_legacy_f32 product before the add
VOP3 0x140 is v_mad_legacy_f32 on gfx10.1. Measured on gfx1010 (RX 5700
XT) in wave32 and wave64, IEEE 0 and 1 and f32 denormal modes 0 to 3, it
rounds the product before the add, flushes f32 denormal sources, product
and result in every mode, and gives a +0 product for a zero factor.

The translation multiplies, applies the zero rule and flushTinyProduct,
adds, and keeps the nanResultF32 wrapper. f32DenormalFlushFor returns 3
for the instruction before reading FLOAT_MODE. A sum of two zeros takes
its sign on the bits, as lavapipe returned -0 for +0 + -0. The execution
test pins the measured results and compares NaN bits exactly. RDNA2
(gfx1031), where the encoding is v_fma_legacy_f32 and fused, is noted in
TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:18:55 +02:00
Adrià 4a01974b09
Merge pull request #1781 from babyhuey/feat/libc-rune-locale
feat(libc): export the C rune locale
2026-10-10 08:18:42 +02:00
Adrià accf6bffc5
Merge pull request #2477 from itsbo5/feat/libScePad-bias-correction
feat(libScePad): implement scePadSetAngularVelocityBiasCorrectionState
2026-10-10 08:18:16 +02:00
Scott Schuster 982849c8ac feat(agc): render into SW_4KB_S_X and SW_4KB_D_X color targets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:18:15 -05:00
Scott Schuster bbf9360305 feat(agc): render into SW_64KB_R_X color targets whose base carries a pipe/bank XOR
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:18:14 -05:00
Scott Schuster 85016605be feat(agc): accept texture BC swizzles that leave the sampled border unchanged
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:17:59 -05:00
Adrià 94ebb80c34
Merge pull request #2458 from gjonn/fix/recompiler-invariant-position
fix(shader): mark the vertex position output invariant
2026-10-10 08:17:50 +02:00
Adrià ecd3dbadb3
Merge pull request #2376 from krishnaraya4/fix/rdna-drop-gcn-vop2-opcodes
fix(shader): stop decoding gfx6/7-only VOP2 opcodes on RDNA
2026-10-10 08:17:22 +02:00
Adrià e53e26a209
Merge pull request #2378 from krishnaraya4/fix/agc-vertex-10-10-10-2-int-class
fix(shader): give 10_10_10_2 integer vertex inputs an integer type
2026-10-10 08:16:57 +02:00
Adrià 5bcbbeb449
Merge pull request #2371 from fisherjoey/fix/scanner-s-bfe-u32
fix(recompiler): apply the S_BFE_U32 width when the vertex fetch scanner folds constants
2026-10-10 08:16:16 +02:00
Adrià 189990dd1f
Merge pull request #2285 from Celegans12/fix/fetch-offset-double-add
fix(shader): count folded draw offsets once in the vertex and instance indices
2026-10-10 08:15:46 +02:00
Adrià e0a311f8e5
Merge pull request #2315 from karanvora2599/perf/shader-min-max-native
perf(shader): pick f32 min, max and med3 results with fewer selects
2026-10-10 08:15:40 +02:00
Adrià dac3aa547f
Merge pull request #2247 from mugurc/macos-nid
feat(nid): patch NIDs in Mach-O libraries
2026-10-10 08:15:03 +02:00
Adrià 3064754c6a
Merge pull request #1547 from russhil/feat/shader-barycentric-emulation
feat(shader): emulate fragment barycentrics with a generated geometry stage
2026-10-10 08:15:00 +02:00
Adrià c94cbb7a58
Merge pull request #2279 from karanvora2599/perf/shader-nan-result-guard
perf(shader): choose the fma NaN result only when the result is NaN
2026-10-10 08:14:57 +02:00
Adrià 40aeb97d57
Merge pull request #1152 from alfalfa-star/perf/linux-direct-memory-import-chunks
perf(agc): share one dma-buf import per 64 MiB of Linux direct memory
2026-10-10 08:14:40 +02:00
Adrià feea78cdd2
Merge pull request #2198 from XairRrR/fix/rect-list-fault-binding
fix(recompiler): bind the rect-list fault buffer in the tessellation control group
2026-10-10 08:14:27 +02:00
fisherjoey 79653e00be fix(shader): carry a packed pixel ancillary through a phi into field extracts 2026-10-10 00:14:18 -06:00
Adrià 21b7876487
Merge pull request #2200 from XairRrR/fix/recompiler-sdwa-v-not-b32
fix(recompiler): accept SDWA destination selects on v_not_b32
2026-10-10 08:14:14 +02:00
Adrià 831e071786
Merge pull request #2199 from XairRrR/fix/recompiler-r8-snorm
feat(agc-driver): sample 8_SNORM images
2026-10-10 08:14:05 +02:00
Adrià 87be948954
Merge pull request #2191 from tezzgod74/fix/spirv-1.3-no-mesh-targets
fix(shader): keep vector selects valid on SPIR-V 1.3 targets
2026-10-10 08:13:36 +02:00
Adrià 4088f7f9a7
Merge pull request #2103 from karanvora2599/perf/shader-redundant-denormal-flush
perf(shader): drop denormal flushes of values that can't be denormal
2026-10-10 08:13:14 +02:00
Adrià dacb0cdd28
Merge pull request #2137 from Sanjaysrinivas/feat/mesh-wave32
fix(shader): support wave32 mesh programs
2026-10-10 08:13:11 +02:00
Adrià 9614e0a602
Merge pull request #2141 from authurtabo-byte/fix/shader-sixteen-sampler-pairs
fix(shader): reserve heap space for sixteen sampler pairs
2026-10-10 08:13:09 +02:00
Adrià 63cd22f395
Merge pull request #2105 from Raghav314/perf/recompiler-post-dominators-postorder
perf(recompiler): compute post-dominators visiting successors first
2026-10-10 08:13:07 +02:00
Adrià 9bb5619c83
Merge pull request #2045 from CouchRiv/fix-shader-div-fixup-flush
fix(shader): flush v_div_fixup_f32 src1 and src2 denormals
2026-10-10 08:12:41 +02:00
Adrià ccedc3a891
Merge pull request #1947 from oguzhanozfe/fix/audio-propagation-singular-path
fix(audio): recognize individual propagation path import
2026-10-10 08:12:21 +02:00
Adrià 692c397a6c
Merge pull request #1854 from Sanjaysrinivas/fix/shader-mode-registers
fix(shader): guard runtime MODE changes
2026-10-10 08:12:00 +02:00
Adrià dbe8961752
Merge pull request #1963 from Deftera186/fix/shader-div-fmas-zero-overflow
fix(shader): return +0 when v_div_fmas_f32 cancels with |src2| >= 2^64
2026-10-10 08:11:36 +02:00
Adrià 7ced89fdcf
Merge pull request #2020 from karanvora2599/perf/shader-constant-factor-tininess
perf(shader): skip the tiny product check that a constant factor settles
2026-10-10 08:10:34 +02:00
Adrià 56bfc4d1c9
Merge pull request #2034 from TheAggie/fix/shader-truncated-decode-out-of-range
fix(shader): report a truncated memory, image or export instruction as out of range
2026-10-10 08:08:33 +02:00
raghav314 c7f4690cd3 fix(agc): host imports write-protect only pages a collect already protects
Importing guest memory collected the write watch over the whole import,
which write-protected every page of it, so pages nothing had collected yet
took a write fault on their first CPU write. The import now collects only
the parts a collect already protects (GuestWriteWatchCollectArmed). The
rest stays unprotected until something collects it, which reports it as
written; a GPU write recorded into such memory (MarkWritten) first collects
the never-collected parts of its 64 KiB blocks
(GuestWriteWatchCollectFresh), so that report is older than the GPU's
results and does not read as a CPU write over them.

Those pages are stamped as written and their CPU pages are noted, but the
block's CPU stamp is left alone, so a GPU label record or a pending storage
image elsewhere in the block does not see a CPU write. StoredOver and
UnchangedSinceCollected read the noted pages whenever a block has them, so
a store to such a page is still seen by a check over that page. The extra
generation step happens only when something was collected; a block whose
write protection fails is unwatched and the write returns no generation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 11:38:28 +05:30
Adrià 2337e0d5d6
Merge pull request #2031 from Aryansh1520/fix/libc-tz-once
perf(libc): set TZ once on Linux
2026-10-10 08:08:28 +02:00
Adrià 9b67cbbd0a
Merge pull request #2022 from NahuelGenchi/fix/agc-unwritten-pixel-program
fix(agc): read an unwritten pixel program address as unset
2026-10-10 08:08:04 +02:00
Adrià 0f84feff1d
Merge pull request #2000 from hansjm10/fix/shader-f16-fma-single-rounding
fix(shader): round the f16 fused multiply-adds once
2026-10-10 08:08:00 +02:00
Adrià 473e64bc8c
Merge pull request #1860 from overlordxrz-source/feat/libkernel-shm-open
feat(libkernel): implement shm_open for anonymous objects
2026-10-10 08:07:24 +02:00
Adrià 3ef8f820af
Merge pull request #2016 from arvindfroi/test/agc-msaa-storage-target
test(agc): check MSAA storage emission without the device's support
2026-10-10 08:07:18 +02:00
Adrià ffd80d7c6a
Merge pull request #2011 from CouchRiv/fix-shader-pk-minmax-clamp-dx10
fix(shader): clamp packed f16 min/max signaling NaN results to zero
2026-10-10 08:07:16 +02:00
Adrià 6324b00b5a
Merge pull request #1979 from Deftera186/fix/shader-sin-cos-exact-reduction
fix(shader): reduce v_sin_f32 and v_cos_f32 inputs exactly
2026-10-10 08:06:46 +02:00
Adrià 35eaa8b253
Merge pull request #1964 from CouchRiv/fix-spirv-continue-backedge
fix(shader): keep runtime image mode switches inside continue targets
2026-10-10 08:06:23 +02:00
Adrià 019ca236fb
Merge pull request #1958 from arcwiser/fix/windows-pe-relocs-stripped
fix(relinker): keep Windows images without relocations loadable
2026-10-10 08:06:20 +02:00
Adrià b86b0b1559
Merge pull request #1966 from Deftera186/fix/shader-ldexp-f16-inline-constants
fix(shader): read v_ldexp_f16 src1 float inline constants as f16
2026-10-10 08:06:15 +02:00
Adrià 832e7b4b6b
Merge pull request #1948 from arcwiser/fix/mimg-unsupported-opcode-diagnostic
fix(shader): name unsupported MIMG opcodes
2026-10-10 08:05:48 +02:00
Adrià a02e0a176f
Merge pull request #1928 from fisherjoey/fix/agc-draw-rectangle-fallback
fix(agc): prepare a rect-list draw's missing rectangle at draw from its prepared stages
2026-10-10 08:05:23 +02:00
eliasbruno124-dev e2401a8dc0 fix(relinker): discover required modules in nested standard directories 2026-10-10 08:05:01 +02:00
Adrià 737e2096ba
Merge pull request #1904 from fisherjoey/fix/shader-ancillary-vector-bfe
fix(shader): lower the packed pixel ancillary when its extract operands fold after it
2026-10-10 08:04:57 +02:00
Adrià 4adefa0708
Merge pull request #1898 from fisherjoey/fix/vop3-add-sub-clamp
fix(shader): saturate VOP3 v_add/sub_nc_u32 and 16-bit add/sub on clamp
2026-10-10 08:04:49 +02:00
turkishcuber a3186c59ef fix(libc): format guest wide strings in swprintf as 16-bit units
The padded, exact-fit and invalid-conversion swprintf checks come from #1512.

Co-Authored-By: Noface07 <yuvrajsoni7@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ULF8vCbJFyzxVsW3SfiWC5
2026-10-10 08:04:44 +02:00
Adrià f3999054bd
Merge pull request #1648 from Pedroj-64/fix/videoout-closed-port-flip-cancel
fix(videoout): cancel flips on a port the title closed instead of failing the driver
2026-10-10 08:03:46 +02:00
Adrià e0526f57cd
Merge pull request #1686 from Cloud-Multiplayer/feat/macos-write-watch
feat(libc): write watch on macOS hosts
2026-10-10 08:03:40 +02:00
Adrià 292ecfb0be
Merge pull request #1734 from TheAggie/feat/agc-texture-pipe-bank-xor
feat(agc): detile XOR-swizzled textures whose base carries a pipe/bank XOR
2026-10-10 08:00:45 +02:00
Adrià 6f51afaa7e
Merge pull request #1736 from TheAggie/feat/agc-color-8888-uint
feat(agc): accept 8_8_8_8 UINT color targets
2026-10-10 07:59:59 +02:00
Adrià 3fcfe82404
Merge pull request #1670 from klosixgaming-arch/bionic/fix-intel-smulextended-v2
fix(shader): work around Intel iGPU OpSMulExtended bug
2026-10-10 07:59:27 +02:00
Adrià 29b4429870
Merge pull request #1485 from Celegans12/feat/agc-10-11-11-unorm-color-targets
feat(agc): implement 10_11_11 unorm color targets through 32-bit uint attachments
2026-10-10 07:58:55 +02:00
Adrià be775231a2
Merge pull request #1651 from emirplus/feat/relinker-tls-register-alu
feat(relinker): support Windows guest TLS reads by ALU register-address instructions
2026-10-10 07:58:52 +02:00
Adrià fc50fde970
Merge pull request #1629 from ahmedhamouda78/feat/agc-dcb-reset-queue
feat(agc): write the measured sceAgcDcbResetQueue packet sequence
2026-10-10 07:58:22 +02:00
Adrià a2236210c3
Merge pull request #1605 from QRMOE/fix/shader-bitfield-mask-overflow
fix(shader): truncate overflowing 32-bit bitfield masks
2026-10-10 07:58:20 +02:00
Zurisen 6d7d4b09e4 test(libkernel): check that a combined flock operation takes an exclusive lock 2026-10-10 07:55:48 +02:00
Zurisen 0f770d2203 fix(libkernel): return EWOULDBLOCK from a contended LOCK_NB flock
flock_nid_postfix threw on every failure, so a LOCK_NB request on a lock
held through another descriptor ended the process. FreeBSD flock(2)
returns -1 with EWOULDBLOCK there. Return guest errno 35 when LOCK_NB is
set and the host reports the lock as held: ERROR_LOCK_VIOLATION on
Windows, EWOULDBLOCK on Linux. Other failures still throw.
2026-10-10 07:55:48 +02:00
Dean 6635c7abbf
Merge pull request #2117 from krishalivaibhav/codex/relinker-help
feat(relinker): support explicit CLI help
2026-10-10 18:54:09 +13:00
Dean e31154aa90
Merge pull request #2196 from AchrafReyani/fix/relinker-entry-point-bounds
fix(relinker): bound the entry point collector's header and symbol reads
2026-10-10 18:54:02 +13:00
Dean cbe83bbd20
Merge pull request #1755 from Zurisen/fix/windows-flock-semantics
fix(libkernel): give flock BSD semantics on Windows
2026-10-10 18:53:55 +13:00
Dean 903863c974
Merge pull request #959 from JAB-dev/feat/ngs2-pan
feat(libSceNgs2.native): implement sceNgs2PanInit and sceNgs2PanGetVolumeMatrix
2026-10-10 18:53:48 +13:00
raghav314 f2bd6d4afd fix(recompiler): emit a formatted buffer access through one function per resource
A formatted buffer load or store whose format comes from a prepared
descriptor emitted the switch over every buffer format inline, at each
access. The switch is now emitted once per resource, component count and
direction as a SPIR-V function taking the index, offsets, record count and
storage buffer offset, and each access calls it. Specialization still folds
the switch to the descriptor's format. Accesses through GPU-selected
descriptors keep the inline switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 11:23:17 +05:30
Scott Schuster 8bba489932 fix(libc): parse fopen and freopen modes as FreeBSD does
FreeBSD's __sflags reads the access character, then b, +, x, e and v, and
stops at the first other character without failing, so "rt" opens for
reading. On Windows fopen inserted b after the first character and passed
the rest on, so "rt" became "rbt", the CRT rejected it with EINVAL, and
fopen threw. vkQuake opens history.txt with "rt" at startup. freopen
accepted only a fixed list of modes.

Both now parse the mode like __sflags. An unknown access character, or x
on a read-only stream, returns NULL with EINVAL; x on an existing file
returns NULL with EEXIST; e and v are accepted and ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:48:13 -05:00
Scott Schuster 456dc87879 feat(libkernel): accept MAP_ALIGNED_SUPER in mmap
An anonymous private mapping with MAP_ALIGNED_SUPER (FreeBSD MAP_ALIGNED(1))
is placed on a 2 MiB superpage boundary. Yamagi Quake II requests it for its
hunk allocations of 2 MiB and more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:47:40 -05:00
Scott Schuster 570aac4677 fix(libkernel): accept SCHED_OTHER in sched_get_priority_max/min
SDL queries the SCHED_OTHER range before it sets a thread priority. It gets
the same 256 to 767 range as SCHED_FIFO and SCHED_RR, which
pthread_setschedparam applies regardless of policy. The console's answer is
unverified and recorded in TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:47:11 -05:00
Scott Schuster b958425977 perf(shader): store multi-dword global writes with one BDA lookup
A global_store_dwordx2/x3/x4 was split into one StoreAddressU32 per
dword, each with its own write-pointer lookup and its own 4-byte store.
Across a wave those are strided partial writes, which are very slow to
host memory: RADV's clear_htile_mask kernel (one dwordx4 load and store
per thread over 640 KiB) took ~9 ms. Multi-dword stores are now one
StoreAddressU32xN; the emitter probes the whole span once and, when it
is mapped writable and 4-byte aligned, stores it as one vector (16- or
8-byte aligned) or as consecutive dwords, noting each written page.
Anything else takes the per-dword path as before, so faults and
range-spanning stores behave as they did. APS5_BDA_DWORD_STORES=1
restores per-dword stores.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:46:34 -05:00
aashishaxo 0e42a60d48 fix(libSceAgcDriver): step over the one-dword NOP pad ffff1000
0xffff1000 is a type-3 NOP whose count field is 0x3fff, which the command processor reads as a single dword. The driver read it as a 16385-dword packet and rejected every sceAgcDcbResetQueue envelope. Pm4::FillerPacket now also matches exactly this header, so every packet walker steps over it as one dword.

Refs #1581
2026-10-10 11:16:13 +05:30
jweidenh c8a23b1ad5 test(relinker): reserve all headers in native execution fixtures 2026-10-10 01:38:08 -04:00
jweidenh 25984a728c fix(relinker): count all synthetic Linux program headers 2026-10-10 01:38:07 -04:00
Dean 001124896d
Merge pull request #2470 from oneandonlydean/up639/cmask-gpu-clear
fix(agc): apply CMASK fast clears per tile
2026-10-10 18:36:56 +13:00
Dean 691c0c3b35
Merge pull request #2451 from oneandonlydean/up639/half-wave-fp-reduce
fix(shader): read lane 63 of a wave64 v_max_f32/v_min_f32 half-wave scan
2026-10-10 18:36:48 +13:00
Dean 25ca708723
Merge pull request #2134 from MarcZX100/codex/fix-pr-overlap-utf8-output
fix(tools): write overlap reports as UTF-8
2026-10-10 18:36:41 +13:00
Adrià Franch 7dec9c9fd8 docs(technical-debt): record the unchanged-bytes baseline of storage write-back
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 07:36:34 +02:00
Dean 0949984e5e
Merge pull request #1945 from TacoCat055/docs/relinker-python-tests
docs: explain relinker Python test discovery
2026-10-10 18:36:32 +13:00
andre 9e06ad7e9d test(agc): run the unchanged CPU stamp case over watched memory and a watched import
The case reached the compared path once host imports kept a guest-byte
snapshot, so it passed without the fix. It now runs over watched memory
without an import on every host, and over a watched host import on Linux
(the font atlas's path, with no valid snapshot), checks the image is on
that path, and runs as its own ctest test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:36:28 +02:00
andrey 1fb59bf4ec test(agc): GPU results survive CPU stamps over unchanged bytes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:36:28 +02:00
andrey dfe147feaa fix(agc): store GPU results over CPU-stamped bytes the CPU left unchanged
A write-back keeps the CPU's bytes for a block stamped since the layer's
generation. Stamps can fall on bytes the CPU did not change (PPSA12544's
font atlas: the stamped pages still hold the allocator fill the image was
uploaded from), and the GPU results there were lost. Images up to 1 MiB
keep the guest bytes of their generation point; a stamped range that still
equals them stores the GPU results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:36:28 +02:00
Dean 71ea4d5ee0
Merge pull request #2248 from MarcZX100/test/agc-untracked-refresh-visibility
test(agc-driver): flush untracked storage results before checking guest memory
2026-10-10 18:36:24 +13:00
Dean 3aae312a4b
Merge pull request #1552 from arvindfroi/test/decoder-length-table
test(relinker): check decoder lengths against an LLVM-generated table
2026-10-10 18:36:17 +13:00
Dean c323d49386
Merge pull request #2052 from esatturan/fix/ajm-atrac9-gapless-segments
fix(ajm): decode an ATRAC9 run's whole input and follow gapless segments
2026-10-10 18:36:09 +13:00
Dean 14469b74e8
Merge pull request #964 from JAB-dev/fix/ngs2-unset-matrix-passthrough
fix(libSceNgs2.native): mix ports without set levels through the default channel map
2026-10-10 18:36:02 +13:00
Dean b7bb2684ec
Merge pull request #1971 from Celegans12/perf/agc-held-texture-residency
perf(agc): keep sampled textures that are bound or used this frame
2026-10-10 18:28:51 +13:00
Dean 9ae2667e08
Merge pull request #1494 from TideOPL/fix/agc-pending-exact-surface
fix(agc): prefer the pending image of exactly a sampled surface over an aliasing mip chain
2026-10-10 18:25:25 +13:00
Achraf Reyani b1599a94ea fix(relinker): bound the entry point collector's header and symbol reads
The CFG/GOT filter's entry point collector checked header and symbol
positions as `offset + size > file size`, which wraps for offsets
near 2^64. A section header or symbol table offset there passed the
check, read bytes before the input buffer, and could reach an
in-bounds table through the wrapped address, adding entry points that
keep relocations alive. Check every position by subtraction instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:23:20 +09:00
JohnM ded18e503f fix(relinker): reject a Linux entry stub whose call cannot reach the entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:22:07 +08:00
Dean Galvin 9c3a35b867 fix(agc): apply CMASK fast clears per tile
A CMASK that was neither all fast-cleared nor all expanded threw, so a
title that fast clears a target and then draws over part of it before the
eliminate could not run past it.

The CMASK is now decoded tile by tile: one nibble per 8x8 tile in
1024x512 metablocks of 4 KiB, addressed with the pipe-aligned
SW_64KB_Z_X CMASK equation for 16 pipes (addrlib
GFX10_CMASK_SW_PATTERN, Gfx10Lib::HwlComputeCmaskAddrFromCoord). Code 0
stores CB_COLOR_CLEAR_WORD into the tile's texels, 0xF keeps them; any
other code, a cleared tile of a DCC target and any other CMASK swizzle
mode throw. Edge tiles are included and the CMASK is then stored as
expanded.

For a resident target whose CMASK is host-imported the clear is a
compute pass recorded in stream order: it reads the nibbles from the
import, stores the clear into the cleared tiles through a UINT view of
the image and fills the CMASK expanded, so nothing waits for pending GPU
writes of the CMASK. Invalid codes it reads set a bit that the next
materialization throws on. Otherwise the CPU reads the CMASK and stores
the cleared tiles into guest memory, or fills the resident image when
every tile is cleared. A CMASK nothing has stored over since it was
expanded is skipped.

The decode requires CB_COLOR_ATTRIB3 FMASK_SW_MODE SW_64KB_Z_X with
CMASK_PIPE_ALIGNED, a 4 KiB aligned writable CMASK and texels of at most
64 bits, and CMASK_BASE_EXT is part of the draw key.

Tests: CMASK sizes and nibble addresses against addrlib; decode
rejections and draw key coverage; CPU eliminate of full, partial,
out-of-range-nibble and DCC decompress cases and invalid codes. The new
agc_driver_cmask_fast_clear GPU test draws over fast-cleared and partly
fast-cleared linear and SW_64KB_R_X targets, eliminates partial, edge
and checkerboard CMASKs through the compute pass and checks that an
invalid code it reads throws.
2026-10-10 18:20:06 +13:00
Dean Galvin 1008b919cc fix(shader): read lane 63 of a wave64 v_max_f32/v_min_f32 half-wave scan
A wave64 vertex program reduces a float key across the wave with the same shape as the integer half-wave reductions: keys selected under the all-lanes EXEC with -inf (v_max_f32) or +inf (v_min_f32) outside the entry EXEC, four DPP row_shr steps, v_permlanex16_b32, then v_readlane_b32 of lanes 31 and 63, combined by one more v_max_f32. On a 32-lane host subgroup the read of lane 63 threw that it is outside the subgroup.

The matcher now also accepts FPMax32 and FPMin32 steps, with their BitCasts and the f32 denormal flush the float mode may add around operands and results; the flush leaves the -inf and +inf keys unchanged. When the entry EXEC proves that lanes 32-63 hold the constant key, every step there combines that constant with itself. The existing v_max_f32/v_min_f32 lowering returns the operand unchanged for equal operands (NaN included), so lane 63 is exactly that constant, and the read returns it. No subgroup float reduction is emitted. Lane 31, the lanes on a 64-lane subgroup, and the combining v_max_f32 keep their existing lowering. So NaN and signed-zero results are the ones the shader computes today.
2026-10-10 18:20:06 +13:00
Dean b667d1e30d
Merge pull request #2328 from TheAggie/fix/libc-collect-writes-whole-range
fix(libc): check a whole range before collecting its writes with reset
2026-10-10 18:19:17 +13:00
Hannah Lyons 64be5f17f7 feat(libc): export the C rune locale 2026-10-10 01:18:44 -04:00
krishalivaibhav 1fc31ba358 feat(relinker): support explicit CLI help 2026-10-10 10:31:52 +05:30
22alfbassett b2b71cd213 fix(libkernel): flush only recorded paths in sceKernelSync on Linux
On Linux, sceKernelSync called sync(2), which blocks until all
dirty pages are written back. Unrelated host I/O can stall guest's
sceKernelSync, causing the guest_kernel_sync test to stall for minutes.

Share the Windows implementation instead.
Fsync each recorded path and its changed parent directories.
Use st_mtim and coarse realtime mark on Linux in place of FILETIME.
2026-10-09 23:55:38 -05:00
raghav314 c903d1adf9 perf(agc): read draw vertex and index buffers in place from host imports
Every draw copied its index range and its vertex ranges out of guest
memory into new host buffers (CopyDrawInput) before the GPU could read
them. A range that lies in a host import is now bound from the import
itself, at its offset in it, the way the console's input assembler reads
guest memory directly.

A range is bound in place only when the batch has no write over it that
could still land (a recorded or in-flight GPU write after the pending
results are flushed, a completion label, a queued label store, a copied
buffer a dispatch or draw writes back) and its offset in the import is a
multiple of what the reader needs: the index size, or the strictest
format alignment of the vertex attributes that share the range
(VertexCopyPlan::alignments; a copy starts its range at offset 0, so
only an in-place range can be misaligned). Otherwise it is copied as
before. The read is noted on the batch (Recorder::ReadKind::DrawInput),
so a CPU store into the range waits for the draw like the other in-place
readers, and the barrier validation sees it. Imports gain vertex and
index buffer usage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:22:58 +05:30
Zurisen d2b8e66c09 fix(libkernel): decode flock operations as FreeBSD does
FreeBSD sys_flock takes LOCK_UN over LOCK_EX over LOCK_SH, ignores other
bits and fails with EBADF when none of the three is set. The operation
reached the host unchanged, so malformed operations differed between
hosts: Linux rejects them with EINVAL and the Windows lock tracking threw.
Decode the operation before either host sees it.
2026-10-10 06:49:20 +02:00
Zurisen 6daf7df9ae fix(libkernel): give flock BSD semantics on Windows
flock mapped each call straight onto LockFileEx/UnlockFileEx, whose
byte-range locks stack per handle. LOCK_UN without a lock failed with
ERROR_NOT_LOCKED and aborted the process, a repeated LOCK_EX blocked
forever, converting between shared and exclusive failed, and a repeated
LOCK_SH needed as many unlocks.

Track the one lock each descriptor holds: a repeated mode and LOCK_UN
without a lock succeed, a conversion releases the old lock before taking
the new one, and close forgets the descriptor's lock.
2026-10-10 06:49:20 +02:00
Dean bc40a6b5a0
Merge pull request #2469 from oneandonlydean/up639/occlusion-in-pass
perf(agc): keep occlusion counter dumps inside the open render pass
2026-10-10 17:47:42 +13:00
Dean 29fe66dfd1
Merge pull request #2450 from oneandonlydean/up639/half-wave-vertex-exec
fix(shader): match half-wave reductions in vertex programs
2026-10-10 17:47:33 +13:00
Dean ff2e6870d9
Merge pull request #2449 from oneandonlydean/up639/half-wave-lane-bits
fix(shader): prove half-wave reduction keys through selected and merged lane bits
2026-10-10 17:47:26 +13:00
Dean 14751060f4
Merge pull request #2357 from NahuelGenchi/fix/apr-submit-unconstructed-buffer
fix(libkernel): submit APR command buffers that were not constructed
2026-10-10 17:47:18 +13:00
Dean cb3aecac97
Merge pull request #2339 from johnmaia/fix/relinker-terminate-frame-chain
fix(relinker): end the guest frame-pointer chain at the entry stub
2026-10-10 17:47:11 +13:00
Dean 568745c091
Merge pull request #2335 from AchrafReyani/fix/directory-utf8-names
fix(libc): read directory entries through the wide dirent API on Windows
2026-10-10 17:47:03 +13:00
Dean ee364bf05f
Merge pull request #2324 from AchrafReyani/fix/libc-getcwd-application-heap
fix(libc): allocate getcwd's buffer from the application heap
2026-10-10 17:46:55 +13:00
Jan Šlégl 9376a0291a docs(shader): record the measured s_call_b64 and null s_swappc_b64 behaviour
Measured on RDNA2 (gfx1036) with tools/hw-oracle in wave32 and wave64:
s_call_b64 writes PC + 4 to the link pair and branches to
PC + 4 + signext(SIMM16) * 4, and s_setpc_b64 of the link returns;
s_swappc_b64 with SDST 125 branches and leaves a marker pair untouched, so
its decode as s_setpc_b64 matches, and with an SGPR destination the link is
PC + 4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-10 06:46:53 +02:00
Dean a7aa802c3e
Merge pull request #2293 from MichonGoddijn231849/fix/agc-prim-state-patch-hs
fix(agc): skip prim state preparation for a patch/hull mismatch
2026-10-10 17:46:48 +13:00
Dean 65bd2f778a
Merge pull request #2289 from AchrafReyani/fix/libkernel-unlink-directory-eperm
fix(libkernel): return EPERM when unlinking a directory
2026-10-10 17:46:40 +13:00
Dean 091505e146
Merge pull request #2284 from eljackjoestar-cmd/codex/pr-shader-module-lifetime
fix(agc): release shader modules after pipeline creation
2026-10-10 17:46:33 +13:00
Dean ac57f46711
Merge pull request #2275 from mrk1987/fix/libkernel-rwlock-concurrent-first-lock
fix(libkernel): initialize guest rwlocks before they are shared
2026-10-10 17:46:25 +13:00
Dean 2c7d2cec17
Merge pull request #2262 from NumberGuan/codex/validate-elf-identification
fix(relinker): validate ELF identification before parsing
2026-10-10 17:46:17 +13:00
Dean 42a1b1d75a
Merge pull request #2256 from NumberGuan/codex/fix-truncated-eh-frame-headers
fix(relinker): reject truncated EH frame headers
2026-10-10 17:46:09 +13:00
Dean af65ea2d8f
Merge pull request #2246 from zmeizy/claude/agc-fail-flips-before-report
fix(agc): fail a failed submission's flips before reporting the failure
2026-10-10 17:46:02 +13:00
Dean a5a4919746
Merge pull request #2245 from NumberGuan/codex/fix-eh-frame-sleb128-overflow
fix(relinker): reject overflowing signed unwind LEB128 values
2026-10-10 17:45:54 +13:00
Dean e2ba429015
Merge pull request #2243 from NumberGuan/codex/protect-relinker-inputs
fix(relinker): protect executable inputs from output overwrites
2026-10-10 17:45:47 +13:00
Dean ae3574bb0d
Merge pull request #2238 from mrk1987/fix/relinker-address-taken-tls-roots
fix(relinker): root code addresses taken by RIP-relative LEA
2026-10-10 17:45:39 +13:00
Dean 698254f048
Merge pull request #2236 from mrk1987/fix/release-direct-memory-unmaps-views
fix(libkernel): unmap direct memory views when the memory is released
2026-10-10 17:45:32 +13:00
Dean 5545196d0e
Merge pull request #2222 from EshaanJaiswal/fix-relative-relocation-bounds
fix(relinker): validate relative relocation table bounds
2026-10-10 17:45:25 +13:00
Dean 1598075951
Merge pull request #2215 from Zheorgyan/fix/debug-log-macro-name
fix(libc): define APS5_LOG_OUT_DEBUG when APS5_DEBUG_LOG is set
2026-10-10 17:45:16 +13:00
Dean a0579f4fba
Merge pull request #2202 from XairRrR/fix/pm4-unbalanced-marker-pop
fix(agc-driver): ignore marker pops without a pushed marker
2026-10-10 17:45:08 +13:00
Dean 5e5c72ee33
Merge pull request #2197 from XairRrR/fix/agc-collapsed-viewport
fix(agc-driver): rasterize nothing through a zero-scale viewport
2026-10-10 17:45:01 +13:00
Dean 6377727dd9
Merge pull request #2179 from oneandonlydean/up639/depth-bounds-absent-planes
fix(agc): pass the depth bounds test when both depth planes are absent
2026-10-10 17:44:53 +13:00
Dean ea8f654350
Merge pull request #2178 from oneandonlydean/up639/resummarize-blits
fix(agc): draw nothing for resummarize draws without depth or color work
2026-10-10 17:44:46 +13:00
Dean 4c39a245a4
Merge pull request #2157 from authurtabo-byte/fix/kernel-localtime-state
fix(libkernel): initialize the full local-time conversion state
2026-10-10 17:44:39 +13:00
Dean 661295e736
Merge pull request #2154 from gunerky/codex/diagnostic-fixture
test(relinker): isolate Windows diagnostic fixtures
2026-10-10 17:44:31 +13:00
Dean b57e66fa60
Merge pull request #2152 from MathiasDevelopes/feat/videoout-pre-vblank-start-events
feat(libSceVideoOut): deliver pre-vblank start events
2026-10-10 17:44:23 +13:00
Dean 5df65b15f6
Merge pull request #2139 from Zheorgyan/fix/agc-quiet-upload-log
fix(agc): remove display upload logs
2026-10-10 17:44:16 +13:00
Dean 7538f22fde
Merge pull request #2128 from MathiasDevelopes/fix/agc-spi-ps-input-cntl-clear-state
fix(libSceAgcDriver): SPI_PS_INPUT_CNTL registers start at their clear-state value
2026-10-10 17:44:08 +13:00
Dean d3c507052a
Merge pull request #2095 from Raghav314/fix/agc-1d-color-targets
fix(agc): render into 1D color targets as one-row 2D targets
2026-10-10 17:44:00 +13:00
Dean 1b5ebc6986
Merge pull request #2091 from treuenten/fix/relinker-callsite-range-wrap
fix(relinker): reject a relocation target whose range wraps the address space
2026-10-10 17:43:52 +13:00
Dean ad0b5ba586
Merge pull request #2090 from LeandroLP23/feat/libkernel-environ
feat(libkernel): export environ as an empty environment
2026-10-10 17:43:44 +13:00
Dean 7cca958a12
Merge pull request #2066 from MarcZX100/codex/fix-agc-optional-prim-register
fix(agc): accept unused geometry output register
2026-10-10 17:43:36 +13:00
Dean 606d4c3d0f
Merge pull request #2063 from MarcZX100/codex/fix-agc-user-data-tail-padding
fix(agc): read shader user data without tail padding
2026-10-10 17:43:28 +13:00
Dean ead855f0cc
Merge pull request #1968 from lubaxe/fix/agc-skip-primitive-restart-index
fix(agc): leave the primitive restart index out of an indexed draw's vertex range
2026-10-10 17:43:21 +13:00
Dean aec0c638a8
Merge pull request #1957 from orbz22/fix/agc-fast-texture-depth-surface
fix(agc): sample resident depth surfaces when a stage-A texture record hits
2026-10-10 17:43:13 +13:00
Dean 9992a5d5e5
Merge pull request #1944 from babyhuey/fix/relinker-lsda-without-personality
fix(relinker): read LSDA call-site tables only under a personality routine
2026-10-10 17:43:06 +13:00
Dean 300bd79439
Merge pull request #1935 from Zinebyte/fix/prefixed-syscall-validation
fix(relinker): reject prefixed system-call instructions
2026-10-10 17:42:59 +13:00
Dean b860fa0c9f
Merge pull request #1929 from MarcZX100/fix/virtualquery-partial-unmap
fix(libkernel): query non-readable live mappings
2026-10-10 17:42:50 +13:00
Dean 9ac075e8c0
Merge pull request #1926 from fisherjoey/fix/exit-teardown-order
fix(ajm, apr): keep AJM and APR state alive through static teardown
2026-10-10 17:42:42 +13:00
Dean 8002d11f67
Merge pull request #1915 from TheAggie/fix/agc-radv-raster-defaults
fix(agc): accept RADV's disabled conservative rasterization and out-of-order watermark
2026-10-10 17:42:34 +13:00
Dean eb283f5c8f
Merge pull request #1914 from TheAggie/feat/agc-force-dst-alpha-one
feat(agc): blend against an opaque destination for CB_COLOR_ATTRIB FORCE_DST_ALPHA_1
2026-10-10 17:42:27 +13:00
Dean a92b3db3d9
Merge pull request #1911 from TheAggie/fix/relinker-empty-tls-guard-access
fix(relinker): convert stack-guard and thread-pointer reads with an empty PT_TLS
2026-10-10 17:42:20 +13:00
Dean c2ebc71c4a
Merge pull request #1893 from fisherjoey/fix/agc-registered-shader-type-8
fix(agc): skip registration-time preparation for unsupported shader types
2026-10-10 17:42:12 +13:00
Dean dd097f9ac6
Merge pull request #1846 from NahuelGenchi/fix/libc-new-handler
fix(libc): call the new handler when operator new fails to allocate
2026-10-10 17:42:04 +13:00
Dean 2061931ac6
Merge pull request #1840 from Prophet069/pr/guest-exception-abi
fix(libc): correct guest exception callback ABI on Windows
2026-10-10 17:41:56 +13:00
Dean 25e4c05b3c
Merge pull request #1836 from EdouardSence/fix/agc-defer-unpreparable-shaders
fix(agc): defer shaders that cannot be prepared at registration to their first use
2026-10-10 17:41:48 +13:00
Dean fdd2d26077
Merge pull request #1830 from tv7/fix/relinker-needed-debug-prx
fix(relinker): match needed module names that differ only in the extension
2026-10-10 17:41:41 +13:00
Dean 8c62529cad
Merge pull request #1822 from eliasbruno124-dev/fix/guest-runpath-depth
fix(relinker): rebase guest runpaths from their output directories
2026-10-10 17:41:33 +13:00
Dean de723ac54b
Merge pull request #1804 from gdrosa/fix/libc-guest-wide-printf
fix(libc): format guest wide printf arguments on Linux
2026-10-10 17:41:26 +13:00
Dean 9c724baad3
Merge pull request #1786 from Zurisen/fix/windows-socket-shutdown-epipe
fix(net): report EPIPE for a send after shutdown on Windows
2026-10-10 17:41:18 +13:00
Dean 5b6c778a95
Merge pull request #1769 from TideOPL/pr/stride0-raw-range
fix(agc): apply the raw OOB_SELECT range rules to zero-stride vertex buffers
2026-10-10 17:41:11 +13:00
Dean a8ce7b7e21
Merge pull request #1727 from SleglJan/feat/libkernel-socket-read-write
fix(libkernel): read and write guest sockets
2026-10-10 17:41:03 +13:00
Dean 47d7ef75dc
Merge pull request #1709 from MathiasDevelopes/feat/agc-dma-data-prefetch
feat(agc): DMA_DATA prefetches to DST_SEL nowhere
2026-10-10 17:40:56 +13:00
Dean 70e66d8efa
Merge pull request #1688 from johnmaia/fix/agc-udmabuf-permission
fix(agc): name the reason when /dev/udmabuf cannot be opened
2026-10-10 17:40:48 +13:00
Dean 6b9f6d52e8
Merge pull request #1658 from morten-holm/pr/exit-guest-handlers-first
fix(libc): run guest exit handlers before the host exit handlers
2026-10-10 17:40:40 +13:00
Dean 1d59f16108
Merge pull request #1653 from morten-holm/pr/moltenvk-no-barycentric
fix(agc): do not use fragment barycentric on MoltenVK
2026-10-10 17:40:33 +13:00
Dean 177332ded0
Merge pull request #1652 from SleglJan/fix/libkernel-signal-mask-bit
fix(libkernel): block guest signals by FreeBSD's bit n - 1
2026-10-10 17:40:25 +13:00
Dean 1f4fd94fa8
Merge pull request #1639 from gerardlesan/fix/agc-zx-mip-tail-limits
fix(agc): use gfx1013's smaller mip tail limits for 8 and 16 bpp SW_64KB_Z_X
2026-10-10 17:40:18 +13:00
Dean 6dbc921d90
Merge pull request #1633 from babyhuey/feat/libkernel-madvise
feat(libkernel): implement madvise
2026-10-10 17:40:10 +13:00
Dean 9fd45aa4fb
Merge pull request #1632 from MarcZX100/fix/amd-proprietary-subgroup-clock
fix(agc): detect AMD proprietary narrow clock
2026-10-10 17:40:02 +13:00
Dean 7879d89f81
Merge pull request #1628 from babyhuey/fix/libkernel-open-directory-flags
fix(libkernel): honour open flags when Windows falls back to a directory descriptor
2026-10-10 17:39:54 +13:00
Dean 80d539abcb
Merge pull request #1562 from hamb3r/codex/fix-unity-suspendpoint-fls
fix(libkernel): keep Unity GC delivery out of MinGW TLS waits
2026-10-10 17:39:46 +13:00
Dean 07633df7fb
Merge pull request #1549 from LeandroLP23/fix/gcc-warnings
fix: clear the GCC warnings in ProfileOutput, fopen, Ajm batch jobs and the SHA-256 test
2026-10-10 17:39:38 +13:00
Dean afb8cd2239
Merge pull request #1609 from krishnaraya4/fix/agc-display-xor-volumes-thick
fix(agc): lay out 3D SW_64KB_D_X textures as thick volumes
2026-10-10 17:19:44 +13:00
Dean 5d02b17767
Merge pull request #2546 from oneandonlydean/ci/ccache-save-main
ci(build): save the compiler cache from main builds
2026-10-10 17:16:28 +13:00
Dean 17874f1177
Merge pull request #2044 from CouchRiv/fix-agc-completion-label-pm4
fix(agc): store labels the GPU cannot reach in stream order
2026-10-10 17:16:19 +13:00
Dean ecc2c8b486
Merge pull request #1865 from fisherjoey/perf/texture-key-ignore-feedback
perf(agc): key sampled textures without the streaming-feedback fields
2026-10-10 17:16:09 +13:00
Adrià Franch c1b714f242 test(libkernel): keep the file stat intact for the lstat checks 2026-10-10 06:14:41 +02:00
Achraf Reyani 610ffbbeba fix(libkernel): report ENOTDIR from stat for a file with a trailing slash
On Windows the existence check accepts "file/", then _wstat64 rejects
it and FillFileStat throws, aborting the title. On Linux the host
reports ENOTDIR, which became ENOENT. A trailing slash on something
that is not a directory now returns ENOTDIR on both hosts, as on
FreeBSD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:14:41 +02:00
Dean Galvin 079f3b759d ci(build): save the compiler cache from main builds
No job saved its ccache, so every build restored a day-old cache and
recompiled about half the tree (971/2038 hits). Main push builds now
save it, and they no longer cancel each other, so one finishes and
refreshes it. Pull request builds still only restore, so PR code never
writes the shared cache.
2026-10-10 16:50:01 +13:00
Achraf Reyani 471e537cdf feat(libc): implement __inet_ntoa
Format the address bytes in network order as dotted decimal into a
per-thread buffer, like FreeBSD's inet_ntoa returns its static one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 12:43:51 +09:00
Dean c72d5ce112
Merge pull request #2537 from oneandonlydean/fix/known-unrun-recorder-tests
fix(ci): restore main's ctest after #1331 and #1496
2026-10-10 16:39:23 +13:00
Achraf Reyani 70d6382e33 fix(libkernel): accept null results in gettimeofday and clock_getres
FreeBSD's gettimeofday stores the time only when tp is not null, and
clock_getres the resolution only when res is not null; both succeed
otherwise. Both threw, which aborted a title probing a clock or only
asking for the time zone. Write into a local result instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 12:24:29 +09:00
Adrià Franch 090a30ca93 docs(debt): end the 3D-on-2D image access line with a period
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 05:17:16 +02:00
Daan Dehing 70d190cdd5 fix(shader): bind 2D textures to 3D sample and load accesses as measured
A 3D image access bound to a 2D T# matched no runtime image mode and
threw "image descriptor is incompatible with the static runtime image
interface" (Sonic Origins, #2023). CouchRiv measured RDNA2 (gfx1036)
with the hardware oracle: image_sample_lz with dim 3D ignores r and
reads the (u,v) texel, and image_load reads the (x,y) texel when z is
0 and returns zero otherwise. Add a 2D mode for 3D accesses whose only
uses are those two forms, and make the load return zero for z != 0.
Every other access keeps throwing.

Fixes #2023

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:15:30 +02:00
Dean Galvin 6266262f33 test(agc): skip agc_pipeline_cache without a Vulkan device
The Windows runner has no Vulkan driver, so agc_pipeline_cache (#1331)
fails at device creation: 'AGC graphics: vkCreateInstance: Vulkan
result -9'. Skip with 77 like the other agc execution tests, unless
ANYPS5_REQUIRE_VULKAN is set, as on the Linux job.
2026-10-10 16:13:01 +13:00
Dean Galvin efdad64047 test(videoout): serialise the tests that share app0/sce_sys/param.json
video_out_flip_tests writes app0/sce_sys/param.json in the shared test
directory on every run, and every VideoOut window reads it for its
title. Under ctest --parallel one test read the file while another
rewrote it: 'unexpected end of param.json' in video_out_flip_controls.
Give all of them one RESOURCE_LOCK.
2026-10-10 16:13:01 +13:00
Dean Galvin 57a7ed801d test(videoout): skip before the first VideoOut call without a display
The unopened-handle checks call sceVideoOutIsOutputSupported before
sceVideoOutOpen, and that first call builds the VideoOut driver, whose
window creation throws without a Vulkan-capable SDL driver. The throw
left main before the skip, so the test aborted on the Linux runner:
'DisplayWindow: Vulkan support is either not configured in SDL or not
available in current SDL video driver (offscreen) or platform'.
Run those checks inside the same skip.
2026-10-10 16:13:01 +13:00
JohnM d1c14102ab fix(relinker): reject a relocation target whose range wraps the address space
A jump slot whose r_offset is 0xFFFFFFFFFFFFFFF8 or higher makes
targetGotOrPltAddress + 8 wrap, so the upper lower_bound lands before
the lower one and the call-site loop walks past the end of the map
(SIGSEGV; ASan heap-buffer-overflow in ResolveCallSites).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 11:03:16 +08:00
Dean Galvin 19d620dec5 test(videoout): skip the output mode test without a display
guest_video_out_output_mode (#1496) opens VideoOut directly, which needs
a Vulkan-capable SDL window, and aborts on the CI runners that have none.
Skip with 77 like the other VideoOut window tests, unless
ANYPS5_REQUIRE_DISPLAY is set.
2026-10-10 15:36:07 +13:00
Joey Fisher 78388c247e docs(debt): record the deliberately leaked AJM, APR and NGS2 state 2026-10-09 20:14:14 -06:00
Joey Fisher f2d201fbbf fix(ajm, apr): keep AJM and APR state alive through static teardown
AJM's instance and batch tables and APR's file, directory and AMM
state were namespace-scope statics, destroyed by std::exit while the
title's threads keep calling the libraries. A decoder thread then read
a freed instance (an unknown codec), sceAjmBatchWait no longer found
its batch, and APR resolved file ids through a freed vector. The state
is now allocated once and never destroyed.
2026-10-09 20:14:04 -06:00
Dean Galvin d1bf5c73de fix(tools): drop agc_driver_recorder_tests from KNOWN_UNRUN
#1331 registered the agc_pipeline_cache ctest, which runs
agc_driver_recorder_tests, without removing that executable from
KNOWN_UNRUN, so check_test_registration fails on main:
'agc_driver_recorder_tests is run by ctest now; remove it from KNOWN_UNRUN'.
The list is empty now; keep it a set for the set operations below.
2026-10-10 15:13:05 +13:00
Raihan Abdul Majid 144e60f836 fix(audioout): play every AudioOut2 port buffer set between pushes, one per grain
A port kept only the last PCM buffer set before a push and played it again
at every later push without a new one. PPSA12544 sets one grain of a ring
buffer per call on its object port, often two or three between pushes and
then none for a few, so all but the last of each burst were dropped and the
stale grain repeated: a buzz on loud sounds and after a sound stopped.

Buffers set between pushes are now queued and played in order, at most 16
queued. A push without a new buffer repeats the last one only for a port
that has always been given the same buffer (rewritten in place, as the
timing tests do); a port whose buffers move on plays silence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:11:23 +07:00
overlordxrz-source e607b1ce4e feat(libkernel): implement shm_open for anonymous objects 2026-10-09 22:05:57 -04:00
Oguzhan Ozdemir 2e01ba2832 fix(audio): bind singular propagation path setter as unsupported 2026-10-10 03:50:02 +02:00
Dean c963432db0
Merge pull request #1645 from XairRrR/fix/raise-open-file-limit
fix(libkernel): raise the open file soft limit on Linux
2026-10-10 14:44:55 +13:00
Dean ee50132692
Merge pull request #1626 from mohdfaour03/fix/sysmodule-unloaded-error
fix(sysmodule): report a module that is not loaded as SCE_SYSMODULE_ERROR_UNLOADED
2026-10-10 14:42:18 +13:00
Dean 771510096f
Merge pull request #1622 from TheAggie/fix/agc-suspend-writes-queued-labels
fix(agc): write queued labels at a suspend point before a device exists
2026-10-10 14:42:08 +13:00
Dean e6f9348b31
Merge pull request #1621 from TheAggie/fix/libc-heap-32-byte-alignment
fix(libc): align guest heap allocations to 32 bytes
2026-10-10 14:41:57 +13:00
validation agent 32eb8b27e3 test(libkernel): cover the scaled process clock origin 2026-10-10 09:28:51 +08:00
hazzardouslysolid fb1eb20ed4 fix(rtc): floor pre-epoch timestamps for timezone lookup 2026-10-10 09:28:30 +08:00
hazzardouslysolid b5903e80da fix(png): bound transparency chunk detection to the input 2026-10-10 09:28:30 +08:00
hazzardouslysolid 7accd92281 fix(libkernel): initialise scaled clock origin before reading time 2026-10-10 09:28:30 +08:00
arcwiser a18955ee97 fix(relinker): keep fixed Windows images loadable 2026-10-10 12:26:02 +11:00
russhil 4a2e60546c feat(shader): emulate fragment barycentrics with a generated geometry stage
Without VK_KHR_fragment_shader_barycentric the recompiler dropped
v_interp_p1_f32 and made v_interp_p2_f32 read the attribute Vulkan
interpolated, but never wrote the I/J VGPRs: a pixel shader that read
them for anything else got 0, and v_interp_mov_f32 of P10/P20 (or P0 of
an interpolated input) needed PerVertexKHR and failed pipeline
validation.

The fallback translation now loads the I/J VGPRs and marks v_interp_p1
and v_interp_p2 with witnesses. After the front-end simplification
(SSA, folding, DCE, read-lane and masked-select elimination),
HostInterpolationChecker requires every p2 to read its J, and its p1's
I, from a barycentric of the parameter's kind, every p1 result to reach
only the matching p2 (through a write masked by the p2's EXEC, whose
inactive lanes keep the old register), no parameter read as raw
vertices and no slot shared by different interpolations. It then
lowers the witnesses to the host-interpolated attribute as before,
reruns DCE and masked-select elimination, and accepts the program only
when no barycentric read remains, so reusing the I/J VGPRs after
interpolating keeps host interpolation and the previous SPIR-V. Any other
program is translated with the barycentric path and marked as emulated:
its barycentrics become vec3 inputs (NoPerspective for the linear
weights) and its per-vertex parameters flat vec4[3] inputs, placed in
the free locations by LayoutBarycentricEmulation. The driver then
inserts a generated geometry stage between the vertex and fragment
shaders that copies the position and parameters, writes the one-hot
weights of each vertex and the three vertices' parameter values, so the
rasterizer interpolates the same weights the extension provides.

The stage needs geometryShader and a vertex shader before it;
tessellation, mesh and rect-list pipelines, other primitive types and
interfaces beyond 32 locations or the device's geometry limits throw.
CompiledShaderArtifact carries the emulation (shader disk cache format 21).

Hardware snaps window corners to 1/256 pixel before interpolating
(measured by yahya308 on an RTX 4070 Laptop and a Radeon 780M in #1547);
lavapipe snaps only for coverage (lp_rast.h FIXED_ORDER 8), so the test
accepts either reference per pixel at the original 1e-4 margin.

Sources:
- v_interp_p1_f32/v_interp_p2_f32/v_interp_mov_f32 semantics (P0,
  P10, P20, I/J): AMD RDNA2 ISA, "Parameter Interpolation".
- BaryCoordKHR/BaryCoordNoPerspKHR weights and PerVertexKHR vertex order:
  SPV_KHR_fragment_shader_barycentric, VK_KHR_fragment_shader_barycentric.
- Geometry shader triangle input order and provoking vertex: Vulkan
  specification, "Primitive Topologies" and "Geometry Shading".
- Interpolation decorations decided by the fragment input: Vulkan
  specification, "Interpolation Decorations".
- lavapipe interpolation: Mesa src/gallium/drivers/llvmpipe/lp_rast.h
  (FIXED_ORDER 8), lp_setup_tri.c (subpixel_snap for coverage only),
  lp_state_setup.c (init_args, plane setup from float positions).
2026-10-10 03:24:50 +02:00
Dean Galvin 7638c11841 perf(agc): keep occlusion counter dumps inside the open render pass
A PIXEL_PIPE_STAT_DUMP event (EVENT_WRITE 0x39, Recorder::DumpSamples)
ended the render pass the previous draw left open: the dump ended the
batch-long occlusion query, copied its result with
vkCmdCopyQueryPoolResults and ran the fold kernel, none of which Vulkan
allows inside a render pass. VulkanDevice::DumpSamplesOnGpu also flushed
the queued store run over the dumped bytes first, which ended the pass
and recorded the run's barriers as well. A title that clears each query
slot with WRITE_DATA and brackets every bounding draw with a begin and an
end dump gets a render pass, two copy barriers and a label run per draw.

Samples are now counted in segments. A segment is one slot of a
per-batch occlusion query pool (128 slots, reset outside any pass when the
batch's first pass needs one). It begins at the first draw recorded after
a pass begins or after a dump, inside that pass's subpass, and ends at the
next dump or right before vkCmdEndRenderPass, so each query begins and
ends in one subpass. A pass whose pool has no free slot left is not
continued, so a new pool can be reset. The draw path that records a whole
pass of its own prepares a slot before its pass and ends its segment
before ending it.

A dump ends the open segment and is queued in the batch's store run with
the number of segments before it; it no longer ends the pass and no
longer flushes the queued stores. The run is recorded where queued stores
already are: at Submit, or earlier when a later command reads or writes
the queued bytes. Its recording copies the results of the segments the
dumps need (one vkCmdCopyQueryPoolResults per contiguous slot range) and
the dump list, then records the queue in groups: a group's stores, then
one dispatch of the SampleDumps kernel, which adds each dump's segments to
the running total and stores the 16 counters in queue order. A store over
bytes a dump of the current group writes starts a new group, so every
byte ends with the value of its last write in program order
(Recorder::QueuedWriteGroups). At Submit, segments no dump consumed are
folded the same way once 64 are pending.

No reader sees a dump later than before: a CPU reader of the dumped bytes
syncs the batch (the dump still notes them as a pending write), and Submit
records the run before the batch ends; a later label or store is queued
after the dump in the same run; GPU work that reads or writes the queued
bytes flushes the run first, as for queued label stores. No reader sees it
earlier either: the dump is recorded after every draw whose samples it
counts, and its segments end at the dump. Without the GPU sample counter
(no buffer device addresses) the batch-long query is kept as before.

Tests (agc_driver_recorder_tests, GPU, run by hand): QueuedWriteGroups
keeps the program order's bytes for 20,000 random store and dump
sequences; a queued dump does not land before its run is recorded, a
reader of other bytes leaves it queued and a reader of its bytes records
it; clear, dump and store orders over shared bytes; two dumps inside one
render pass keep it open (the next draw continues it) and split its three
draws' samples exactly with precise queries; a reader flushing a dump
inside a pass ends the pass; 160 dumps in one pass past a pool's 128
slots; 70 passes without a dump folded at Submit.
2026-10-10 14:24:27 +13:00
Dean Galvin 77373c0380 fix(agc): pass the depth bounds test when both depth planes are absent
Main renders depth and stencil tests without a depth target when DB_Z_INFO and DB_STENCIL_INFO both have FORMAT INVALID (48ebf3195e): with no plane, the DB has nothing to test, and every test passes. The depth bounds test (DB_DEPTH_CONTROL bit 3) reads the same absent depth plane, but such a draw still threw "depth bounds without a depth surface". A title does this when a level loads.

Depth bounds now follow the same rule when both planes are absent. With an absent depth plane beside a present stencil plane, the bounds test still throws ("depth bounds without a depth plane"), as before.
2026-10-10 14:24:26 +13:00
Hannah Lyons c970ca73a0 fix(relinker): read LSDA call-site tables only under a personality routine 2026-10-09 21:23:27 -04:00
Hannah Lyons d7e52cb295 feat(libkernel): implement madvise 2026-10-09 21:22:44 -04:00
Hannah Lyons 94a33bfa5c fix(libkernel): honour open flags when Windows falls back to a directory descriptor 2026-10-09 21:22:23 -04:00
alfalfa-star b7443c4424 perf(agc): share one dma-buf import per 64 MiB of Linux direct memory
Every direct memory allocation had a memfd of its own, so each one the
GPU used became its own udmabuf and its own imported buffer object. An
imported buffer object cannot be always valid in the GPU VM: amdgpu
validates every one of them at every command submission. PPSA14632
(LEGO Horizon Adventures) imports about 7000 allocations, 5800 of them
64 KiB, and each vkQueueSubmit took about 2.3 ms (5 s per 10 s, held
under the GPU mutex). A standalone test shows the cost follows the
count of imported dma-buf buffer objects, not their size or the count
of ordinary allocations.

- libkernel: on Linux all direct memory lives in one sparse memfd of
  DIRECT_MEMORY_SIZE, at file offset = physical address
  (PhysicalBacking keeps the file and its offset; SharedBacking returns
  that offset). A range allocated again is zeroed through a temporary
  mapping, as the old per-allocation memfd was.
- Driver: an import of shared direct memory that lies inside one
  64 MiB chunk of the file binds its own VkBuffer into that chunk's
  memory, one udmabuf import per chunk (HostImport::chunk holds it, so
  it lives until the last buffer bound to it retires). Ranges that
  cross a chunk or do not meet the buffer alignment are imported alone
  as before.

On PPSA14632 vkQueueSubmit drops from about 2400 us to 46 us on
average, the GPU idles 36 ms instead of 172 ms per present, and
presents go from about 40 to 80-97 per 10 s.

Released direct memory stays committed in the file (see
TechnicalDebt.md): a live chunk import pins its pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:21:53 +02:00
Adrià Franch 4120b2be0f docs(architecture): keep the recompiler stage notes under their diagram
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 03:16:29 +02:00
Sanjaysrinivas 140c46093c fix(shader): guard runtime MODE changes
Read MODE rounding fields from the declared initial mode. Accept only
constant writes that preserve it; diagnose unsupported runtime changes.
Document the supported contract and add decoder-to-recompiler regressions.

Refs #1668, #981
2026-10-10 03:16:25 +02:00
Adrià c9da0f93cf
Merge pull request #1559 from ctj01/fix/relinker-pt-load-order
fix(relinker): write Linux PT_LOAD headers in ascending address order
2026-10-10 03:16:06 +02:00
Adrià 67bb99865a
Merge pull request #1518 from ArjenS-LA/fix/windows-file-timestamps
fix(libkernel): preserve Windows file timestamp precision
2026-10-10 03:15:32 +02:00
Adrià 426fe62282
Merge pull request #2028 from overlordxrz-source/feat/libkernel-get-module-list
feat(libkernel): implement sceKernelGetModuleList and sceKernelGetModuleInfo
2026-10-10 03:15:01 +02:00
Adrià 419069e6d3
Merge pull request #1606 from mohdfaour03/fix/libc-guest-tm-layout
fix(libc): convert times into the guest's 56-byte tm on Windows
2026-10-10 03:14:40 +02:00
Adrià b255a3b998
Merge pull request #1604 from Zheorgyan/fix/host-thread-local-async-teardown
test(libc): wait for std::async thread teardown in host_thread_local
2026-10-10 03:14:22 +02:00
Adrià 2d58760056
Merge pull request #1602 from krishnaraya4/fix/agc-linear-volume-mip-rounding
fix(agc): round linear volume mip extents up as addrlib does
2026-10-10 03:14:01 +02:00
Adrià 6637eee34d
Merge pull request #1600 from awake-devel/fix/libkernel-unwind-info-linux
fix(libkernel): report guest unwind tables in sceKernelGetModuleInfoForUnwind on Linux
2026-10-10 03:13:40 +02:00
Adrià 3181e7116d
Merge pull request #1597 from mugurc/macos-relinker
feat(relinker): write Mach-O output for macOS with --macos
2026-10-10 03:13:21 +02:00
Adrià 16602061e0
Merge pull request #1589 from krishnaraya4/fix/rdna-mubuf-lds-refused
fix(shader): refuse the MUBUF lds modifier instead of decoding a VGPR load
2026-10-10 03:13:01 +02:00
Adrià d11caf7519
Merge pull request #1588 from Roojool/fix/net-epoll-precise-timeout
fix(net): use native Windows condition waits for empty epoll
2026-10-10 03:12:41 +02:00
Adrià b2f4218ad2
Merge pull request #1587 from krishnaraya4/fix/agc-release-mem-int-sel-bounds
fix(libSceAgcDriver): read the RELEASE_MEM interrupt select only from RELEASE_MEM packets
2026-10-10 03:12:22 +02:00
Sasha Papo 98b4bdf843 fix(agc): skip an indexed draw whose indices are all restart markers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:12:16 -04:00
Sasha Papo c0a88ce392 fix(agc): leave the primitive restart index out of an indexed draw's vertex range
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:12:16 -04:00
Adrià a9ac7bc4c3
Merge pull request #1580 from Zheorgyan/feat/storage-buffers-update-after-bind
feat(agc): bind storage buffers update-after-bind above the per-stage limit
2026-10-10 03:12:01 +02:00
Adrià b9d7fd6448
Merge pull request #1571 from Zheorgyan/fix/exp-f32-smallest-normal
fix(shader): keep v_exp_f32 at or above the smallest normal for inputs from -126
2026-10-10 03:11:42 +02:00
Elijah De Guzman 80b0bab279 feat(libc): write watch on macOS hosts
macOS has no counterpart to userfaultfd write-protect or
MEM_WRITE_WATCH, so GuestWriteWatch had no backend there and the driver
re-read every guest buffer on each use.

The macOS backend write-protects watched pages. The first write to a
page faults, the SIGBUS/SIGSEGV handler records the page and restores
its protection, and Collect reports the recorded pages and protects
them again. A page is protected before its record is cleared, under the
lock the handler takes, so a write that lands in between is recorded.
The lock hands out turns in order: an unfair one starved writers under
Rosetta.

The protection is real, which adds three entry points:
- GuestWriteWatchBeginHostWrite/EndHostWrite lift it around a system
  call that writes guest memory, which would otherwise fail with
  EFAULT. GuestArena::HostWrite calls them, as it calls the Windows
  equivalent.
- GuestWriteWatchProtectionChanged tells the watch the protection given
  to watched pages by mprotect or a new mapping.
- GuestWriteWatchProtection reports that protection, since a watched
  page is read-only between a collection and the next write.

Register keeps the recorded protection of a page it already watches:
read from the kernel it would be the watch's own read-only protection,
and the page would never be watched again.

The tests build without the prx libraries and run natively and through
Rosetta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:11:40 -04:00
Adrià 206df95c36
Merge pull request #1565 from Zheorgyan/fix/exec-host-lanes-vertex-subgroups
test(agc): skip the exec host lanes vertex draw without vertex subgroups
2026-10-10 03:11:21 +02:00
Dean 8542c7323c
Merge pull request #1501 from TideOPL/fix/kernel-process-time-start
fix(libkernel): read the process start before the clock in process time
2026-10-10 14:10:57 +13:00
Adrià 527b18ea59
Merge pull request #1556 from MarcZX100/docs/fedora-static-cmake-deps
docs(build): note Fedora static link packages
2026-10-10 03:10:35 +02:00
Adrià 7876b46ff3
Merge pull request #1534 from hamb3r/codex/clearmrt-stencil-clear
fix(agc): preserve ClearMRT color writes and validate stencil clears
2026-10-10 03:09:58 +02:00
Adrià 69cee68d4b
Merge pull request #1522 from silentone12725/perf/relinker-strict-reachability
perf(relinker): replace O(n²) zero-padding scan in StrictReachability
2026-10-10 03:08:57 +02:00
Adrià b8cf0eb24f
Merge pull request #1520 from popcoder565/fix/kernel-nested-sleep-timer
fix(libkernel): give a sleep nested in an APC its own timer on Windows
2026-10-10 03:07:46 +02:00
Adrià 7f1b6a0b30
Merge pull request #1507 from ArjenS-LA/fix/libc-wcsrtombs
fix(libc): convert wcsrtombs using guest characters
2026-10-10 03:05:55 +02:00
Adrià 395d24697c
Merge pull request #1506 from kali113/fix/linux-guest-stack-header
fix(relinker): give Linux guest modules a default non-executable stack
2026-10-10 03:05:35 +02:00
Adrià be3441903b
Merge pull request #1503 from eliasbruno124-dev/fix/guest-required-identities
fix(relinker): discover required guest module identities
2026-10-10 03:05:15 +02:00
Adrià 0eb7f098dd
Merge pull request #1499 from yabanana/codex/macos-unwind-register-context
feat(libc): support x86-64 unwind register contexts on macOS
2026-10-10 03:04:54 +02:00
Adrià 85d4bfcf34
Merge pull request #1496 from hugodearaujo/fix/videoout-output-mode-errors
fix(videoout): answer output mode queries with the console's codes
2026-10-10 03:04:33 +02:00
Adrià 806ff29e5a
Merge pull request #1495 from TideOPL/fix/agc-depth-memory-reuse
fix(agc): treat other-shaped views of a depth surface's memory as reused memory
2026-10-10 03:04:14 +02:00
Adrià 7703fda15e
Merge pull request #1493 from LeandroLP23/refactor/controlflow-shared-helpers
refactor(recompiler): share the control flow helpers
2026-10-10 03:03:41 +02:00
Adrià ba6f1e5bd6
Merge pull request #1487 from Celegans12/feat/agc-forced-degamma-srgb
feat(agc): accept samplers that force sRGB decoding of sRGB textures
2026-10-10 03:03:19 +02:00
Adrià e0d4516b43
Merge pull request #1486 from popcoder565/fix/audio-precise-pacing
fix(audio): pace blocking audio calls with a high-resolution timer
2026-10-10 03:03:00 +02:00
Adrià 3fe03f7227
Merge pull request #1473 from LeandroLP23/fix/shader-lg-compare-amd-wave32
fix(shader): emit ordered not-equal through an integer NaN check
2026-10-10 03:02:02 +02:00
Adrià b993145df1
Merge pull request #1446 from sktharunbalaji13-cmd/contrib/rela-table-bounds
fix(relinker): bound DT_RELA table range
2026-10-10 03:01:42 +02:00
Adrià 5a014b888a
Merge pull request #1417 from gjonn/feat/agc-fold-constant-swizzle-samples
feat(agc): fold samples of views whose channels all select constants
2026-10-10 03:01:21 +02:00
Adrià 7fae9c8f00
Merge pull request #1331 from TibixDev/pr/pipeline-key-storage
perf(pipeline): reuse key storage and hash keys in blocks
2026-10-10 03:00:46 +02:00
Adrià dcfd4f658f
Merge pull request #1328 from darhebkf/codex/fix-nid-cache-download
fix(tools): publish NID database cache after download completes
2026-10-10 03:00:27 +02:00
Celegans12 0eebe23a12 perf(agc): reuse frontend within shader registration pairs
Retain an immutable decoded program and structured control flow while
preparing the registration variants for one shader.
Match owned code, stage and the complete SWAPPC inputs before reuse.
Translate and plan each variant separately using its current inputs.
Keep cache keys and persisted artifact layouts unchanged.
Provide a cache-neutral off switch for controlled comparisons.
Cover identity, lifetime, failed replacements and variant equivalence.
2026-10-10 02:53:50 +02:00
Dean 0c0dc1e98e
Merge pull request #2514 from adriadam10/fix/linux-ci-display-skips
fix(ci): skip the VideoOut window tests without a display, as check_skips expects
2026-10-10 13:52:04 +13:00
Adrià Franch 94a1d0b20a fix(ci): accept no-display skips in the Windows job too
The Windows runner has no Vulkan driver, so the VideoOut window tests skip there for the same reason; check_skips.py
only accepted agc* skips in that job.
2026-10-10 02:38:24 +02:00
Adrià Franch df270d59eb fix(ci): skip the VideoOut window tests without a display, as check_skips expects
Main's Linux job fails since #1028 and #1714: guest_video_out_resolution_status aborts when SDL's offscreen
driver has no Vulkan window, and check_skips.py rejects the skips of guest_video_out_wqhd_detection and the
flip tests because "no display" is not among the device limitations it accepts.

The resolution status test now skips with code 77 like its wqhd sibling, the flip tests print the same skip
reason, and check_skips.py accepts "no display" as a device limitation. ANYPS5_REQUIRE_DISPLAY still turns
the skip into a failure.
2026-10-10 02:20:49 +02:00
Adrià Franch 6fee7e854d docs(shader): record the bitfield mask measurement on gfx1035
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 02:14:00 +02:00
Adrià Franch 7e845c124b test(shader): skip the bitfield mask execution test below 32-lane subgroups
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 02:14:00 +02:00
QRMOE 9fbb5a9f13 docs(shader): place bitfield debt with shader entries
AI-assisted: yes. Full current-main project build passed. Seven focused Windows tests pass; four shader tests also pass in full and none optimization modes with actual Vulkan execution required. Updated Linux and title runs remain pending.
2026-10-10 02:13:51 +02:00
QRMOE fc254615a1 test(shader): use raw bounds checking for bitfield buffers
AI-assisted: yes. Full current-main project build passed. Seven focused Windows tests pass; four shader tests also pass in full and none optimization modes with actual Vulkan execution required. Updated Linux and title runs remain pending.
2026-10-10 02:13:44 +02:00
QRMOE f2f442a364 test(shader): register bitfield mask translation test
Register the regression with CTest and configure Windows runtime lookup. AI-assisted: yes.
2026-10-10 02:13:34 +02:00
QRMOE 4eb23fc2f3 test(shader): execute scalar and vector bitfield masks
Exercise 4096 width/offset inputs through Vulkan and preserve both SCC values. AI-assisted: yes.
2026-10-10 02:13:34 +02:00
QRMOE f7f987cf74 test(shader): cover bitfield-mask boundary folding
Cover all width/offset pairs and independent ignored upper operand bits for scalar and vector masks. AI-assisted: yes.
2026-10-10 02:13:34 +02:00
QRMOE e65a707f61 fix(shader): truncate overflowing 32-bit bitfield masks
Construct the low-bit mask at offset zero, then shift it in 32-bit arithmetic. AI-assisted: yes.
2026-10-10 02:13:34 +02:00
Mohd Faour 0aae158635 fix(libc): convert times into the guest's 56-byte tm on Windows
gmtime, localtime, mktime, strftime and asctime took and returned the
host std::tm. The guest's FreeBSD tm has tm_gmtoff and tm_zone after the
nine calendar fields, so on Windows, where std::tm is 36 bytes, a title
reading those fields read past the thread-local result, and gmtime_s left
them unwritten. Windows gmtime_s also accepts only 1969-12-31 12:00 to
3001-01-19 21:59 UTC, where the guest libc converts any time.

Convert through a GuestTm with the guest layout on both hosts. Compute
the UTC fields from the day count, so every time whose year fits an int
converts, and on Windows take the local offset and zone name from the
CRT. gmtime reports the zone as UTC like the guest libc. localtime and
mktime keep the CRT's range on Windows; recorded in TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 02:13:17 +02:00
Adrià 1f0c9fef56
Merge pull request #2473 from Celegans12/fix/videoout-vrr-duplicate-export
fix(videoout): remove duplicate VRR exports
2026-10-10 02:10:59 +02:00
Adrià Franch 78d92881b0 fix(libkernel): throw when the Linux guest unwind lookup fails
As requested in review: a failed sceKernelGetModuleInfoFromAddr no longer
reports an empty answer. Adds a failure test (symbol interposition) and
extends the metadata test (EH record walk, terminator, no-header DSO).

Co-authored-by: jweidenh <38249793+jweidenh@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 02:10:08 +02:00
clem-gb 1bd1923718 fix(libkernel): report guest unwind tables in sceKernelGetModuleInfoForUnwind on Linux
A title that ships its own libc.prx unwinds C++ exceptions with that
libc's libunwind, which asks sceKernelGetModuleInfoForUnwind where each
frame's eh_frame is. On Linux the call always reported no tables, so
no C++ exception thrown in guest code could be caught. For the main
executable and .guest.prx images, report the PT_GNU_EH_FRAME tables
that sceKernelGetModuleInfoFromAddr finds, as Windows does from
.ehmeta. Other host images still report none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-10 02:09:56 +02:00
ed a83bfa6813 fix(hw-oracle): select the AMDGPU ELF emulation when linking kernels
LLD built for a MinGW host runs the COFF linker when ld.lld gets no -m option,
so it rejects the AMDGPU object with "unknown file type" and the
hardware_oracle test fails on Windows with WinLibs LLVM in PATH. Passing
-m elf64_amdgpu selects the ELF linker on every host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:09:53 -07:00
Arvind Frøiland 258cfddaf5 test(relinker): keep only the generated decoder length table
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:09:38 +09:00
Celegans12 c4b7a7453e feat(agc): implement 10_11_11 unorm color targets through 32-bit uint attachments
CB_COLOR_INFO format 6 (COLOR_10_11_11) with NUMBER_UNORM threw in
DecodeColorFormat: Vulkan has only the B10G11R11 float format. Such a
target now renders into an R32_UINT attachment in the layout of
format-30 images (unorm11 R and G in bits 0-21, unorm10 B in bits
22-31), so later image loads of the surface read the same words.

The target format is draw state, so the packing is a specialization of
the registered pixel shader: every float MRT export also computes the
packed word (EmitFormatStoreComponent) behind specialization constant
ExportPackingBase + target, and the specialized module turns a packed
target's output into a uint4 that ValidateShaders expects. The new
request field targetExportPacking is in the module key, the result memo,
the draw key and the serialized request (version 14). Blending, partial
RGB writes, UNORM16/SNORM16/UINT16 exports, DCC and ROUND_MODE throw.
2026-10-10 02:09:27 +02:00
Zheorgyan 27e6ad1ad2 feat(agc): bind storage buffers update-after-bind above the per-stage limit 2026-10-10 02:08:15 +02:00
hamb3r 14f5572fca test(libkernel): cover exception delivery during mutex wait 2026-10-10 03:06:48 +03:00
hamb3r 2d783b7962 fix(libkernel): keep Unity GC delivery out of MinGW TLS waits 2026-10-10 03:06:40 +03:00
Adrià Franch bb54bffeaa fix(net): lock the memory pool stats with the host mutex type 2026-10-10 02:06:08 +02:00
Roojool a0f42946e5 fix(net): use native Windows condition waits for empty epoll 2026-10-10 02:05:23 +02:00
TideOPL 3fba616bb5 test(agc): look up a pending surface aliased by a pending mip chain
agc_driver_pending_exact_surface writes mip 0 of a 2-mip 256x256 surface and then a 1-mip surface at the same address. The chain's mip 0 lies past the 1-mip surface's bytes, so both images stay pending, the chain first. A lookup of the 1-mip size must return the 1-mip image, and with only the chain pending it must still return the chain. On main the first lookup returns the chain.
2026-10-10 01:03:15 +01:00
Zurisen 2356aba27b fix(net): report EPIPE for a send after shutdown on Windows
Winsock fails send, sendto and sendmsg on a socket shut down for writing
with WSAESHUTDOWN, which neither Windows error map handled, so libkernel
and libSceNet reported EIO. FreeBSD reports EPIPE there, and the Linux
maps already translate the host's EPIPE to 32. Map WSAESHUTDOWN to 32
in both.
2026-10-10 02:02:29 +02:00
TideOPL c52c005858 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into fix/agc-pending-exact-surface 2026-10-10 01:00:17 +01:00
ArjenS-LA 705e49d407 fix(libkernel): preserve Windows file timestamp precision 2026-10-10 01:51:56 +02:00
TideOPL 46606e9c73 test(agc): cover depth surface lookups of reused memory
agc_driver_graphics registers a D32 and a D16 surface on a mock device and looks up views at their addresses. Views of the surface's own extent in R32F or R16, and T#s that read the raw depth bits, sample the depth plane; a view of another extent, a 2D array view of another extent, an R11G11B10 view, an R32 uint view without a depth layout and an R32F view of a D16 surface return null and take the ordinary texture path. On main the first of these throws in DepthSurface::Sampled.
2026-10-10 00:44:40 +01:00
hugodearaujo cadcbfd3a8 fix(videoout): answer output mode queries with the console's codes
Measured on a PS5 (firmware 13.60) through dlopen of
libSceVideoOut.sprx on a handle the payload opened.
sceVideoOutInitializeOutputOptions writes 0xFF to byte 2 of the 64-byte
options and returns INVALID_ADDRESS for a null pointer.
sceVideoOutIsOutputSupported checks the handle, then the reserved
arguments, then the mode, then the options. It never answers 0: a mode
the display lacks returns UNSUPPORTED_OUTPUT_MODE, and a value that is
not a mode returns 0x8029001E. Options must keep the initialized words,
except word 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:42:40 +02:00
overlordxrz-source 8a41d280af feat(libkernel): implement sceKernelGetModuleInfo
Fill takes either info struct, so sceKernelGetModuleInfo reports the
name and segments sceKernelGetModuleInfoFromAddr reports for the same
image, on Linux and Windows.
2026-10-09 19:39:49 -04:00
overlordxrz-source 6d42f3a910 feat(libkernel): implement sceKernelGetModuleList 2026-10-09 19:39:49 -04:00
Adrià Franch ec2df2691a docs(tech-debt): record the FORCE_DEGAMMA measurement on RDNA2
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 01:38:23 +02:00
Celegans12 619ec7ad39 feat(agc): accept samplers that force sRGB decoding of sRGB textures
A sampler with FORCE_DEGAMMA (S# word 0 bit 20) threw at decode, so
every dispatch or draw sampling through one was skipped.

DecodeSamplerResource now records the bit, but accepts it only for a
caller that pairs the sampler with its images. The direct sampler
binding does, and RequireDegammaFormat checks each sampled image
against its paired samplers: only already sRGB formats (8, 8_8 and
8_8_8_8 SRGB, BC1, BC2, BC3 and BC7 SRGB) pass, decoded once, as
shadPS4 (PS4) models it. Other textures and unpaired decodes still
throw; gfx10 behaviour is not measured.
2026-10-10 01:38:17 +02:00
TideOPL 430b8e0e36 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into fix/agc-depth-memory-reuse 2026-10-10 00:38:01 +01:00
Adrià a291ae0f88
Merge pull request #1483 from Aryansh1520/fix/libkernel-mutex-destroy-busy
fix(libkernel): return EBUSY when destroying a locked mutex
2026-10-10 01:32:32 +02:00
popcoder565 b2cde4a0f2 fix(audio): pace blocking audio calls with a high-resolution timer
On Windows, nanosleep and this_thread::sleep_for/sleep_until go
through winpthreads, which ends a wait on a 15.6 ms GetTickCount64
step. Blocking sceAudioOutOutput and sceAudioOut2ContextPush calls
returned in bursts about every 16 ms, a blocking sceAudio3dPortPush
ran at about 68 % of real time, and sceAudioInInput without a device
woke anywhere from 1 ms to 31 ms apart. They now sleep with
PreciseSleepUs or the new PreciseSleepUntil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:31:57 +02:00
Adrià 787239eca5
Merge pull request #1459 from nauroth/claude/strtol-c17-prefix
fix(libc): stop the strtol family at a binary prefix on Linux
2026-10-10 01:31:16 +02:00
Jan Šlégl c26c1cae5b fix(libkernel): block guest signals by FreeBSD's bit n - 1
sigprocmask keeps the first word of the title's set as it is, where
FreeBSD keeps signal n at bit n - 1 (_SIG_BIT), but Dispatch tested bit
n. A title that blocked SIGTERM with a FreeBSD-built set (bit 14) was
not protected, and a set with bit 15 blocked SIGTERM instead of SIGURG.
Dispatch now tests bit n - 1; the stored mask and the set returned by
sigprocmask are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-10 01:30:55 +02:00
Adrià 5cb716a6a3
Merge pull request #1351 from MarcZX100/test/register-file-streams
test(libc): register file stream coverage
2026-10-10 01:30:36 +02:00
Adrià 2edaf7f460
Merge pull request #1310 from TibixDev/pr/write-tracking-range-scans
perf(memory): reduce repeated write-tracking range scans
2026-10-10 01:29:30 +02:00
Adrià b02ea5f5ea
Merge pull request #1309 from TibixDev/pr/tracked-backing-writes
perf(memory): write tracked direct memory through backing views
2026-10-10 01:29:11 +02:00
Adrià Franch 8404c4987d docs(technicaldebt): move the ordered not-equal line away from the f32 denormal entries
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 01:28:00 +02:00
Adrià ff8961dfbc
Merge pull request #1102 from jeffrey12cali/fix/module-args-on-linux
fix(libkernel): pass module args and argp to runtime-loaded modules on Linux
2026-10-10 01:27:59 +02:00
Adrià bb1a726e6e
Merge pull request #1466 from LeandroLP23/fix/kernel-download0-at-start
fix(kernel): create /download0 at start-up when the title declares download data
2026-10-10 01:27:57 +02:00
LeandroLP23 4f03d9f4d6 fix(shader): emit ordered not-equal through an integer NaN check
The AMD Windows driver returns 1 for a NaN operand when any float form
of ordered not-equal feeds a ballot on a 32-wide subgroup, which is how
e32 compares are read in wave32. FPOrdNotEqual32 is now emitted as an
unordered not-equal with both operands checked for NaN on their bits,
which gives the same result for every input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:27:52 +02:00
Tharun Balaji 204a5e7a42 test(relinker): cover relocation table bounds in C++ under both output modes 2026-10-10 01:26:27 +02:00
Tharun Balaji bef3286e81 fix(relinker): bound DT_RELA table range 2026-10-10 01:26:27 +02:00
Adrià 8c6780d606
Merge pull request #1300 from TibixDev/pr/ngs2-atrac9-streaming
fix(ngs2): decode ATRAC9 across streamed waveform blocks
2026-10-10 01:25:02 +02:00
Adrià 76bff21fbe
Merge pull request #1421 from popcoder565/fix/kernel-raise-exception-ntcontinue
fix(libkernel): stop losing and deadlocking sceKernelRaiseException deliveries on Windows
2026-10-10 01:23:17 +02:00
Adrià Franch 995de0c819 fix(agc): bump the shader disk cache format version for the new image fields
The ImageResource layout change needs its own version: main is already at 21.
2026-10-10 01:22:28 +02:00
Gjon Gojcevic e8b24afecd feat(agc): fold samples of views whose channels all select constants
When every dst_sel of a sampled view selects constant 0 or 1, a sample
or gather returns that constant whatever the texel, filter, LOD or
coordinates. Such placeholder views can have a dimension the static
runtime image interface has no mode for (a 3D view under a 2D sample,
a 1D view under a 2D gather), and a 3D one paired with an unnormalized
sampler fails the unnormalized proof.

A direct sampled image whose accesses are all non-compare samples or
gathers gets three constant runtime modes (float, uint, sint). The mode
is selected when all four dst_sel are 0 or 1, unless the view is FMASK,
depth bits, converted or sRGB-decoded. In it the emitter returns each
channel's constant (the dmask channel's, in all four texels, for a
gather) from the image's swizzle specialization constants, and the
image is left unbound. ProveUnnormalized skips the mode after the
run-time-selected check, so table roots still throw.
2026-10-10 01:22:21 +02:00
Adrià 32064d31fc
Merge pull request #1401 from xsvm/perf/relinker-in-place-substitutions
perf(relinker): write in-place --to-intel substitutions directly
2026-10-10 01:21:28 +02:00
Adrià c5424ab69c
Merge pull request #1916 from johnmaia/feat/libkernel-sigaction
feat(libkernel): implement sigaction
2026-10-10 01:20:54 +02:00
Adrià d992f76744
Merge pull request #1335 from TibixDev/pr/uniform-pattern-fill
perf(agc): handle uniform pattern-fill kernels as clears
2026-10-10 01:20:53 +02:00
Adrià 00dd2ba844
Merge pull request #1017 from NahuelGenchi/fix/v-fma-f64-subnormals
fix(shader): round v_fma_f64 once for subnormal operands and results
2026-10-10 01:19:26 +02:00
Adrià a12eda11f4
Merge pull request #1280 from TheAggie/perf/recompiler-bda-note-load
perf(recompiler): load the written-page slot before the CAS
2026-10-10 01:18:05 +02:00
Adrià 5cb747c146
Merge pull request #1260 from MarcZX100/fix/savedata-file-clock-compat
fix(SaveData): use C++20 file clock conversion
2026-10-10 01:11:50 +02:00
Adrià 58706dc2d9
Merge pull request #1225 from Pedroj-64/fix/video-out-present-shutdown-failure
fix(videoout): report GPU driver shutdown failure from the present thread at Shutdown
2026-10-10 01:10:19 +02:00
Adrià 624b2b7eff
Merge pull request #1135 from orbz22/fix/kernel-aio-keep-offset-windows
fix(kernel): keep the file offset in Windows AIO reads and writes
2026-10-10 01:09:52 +02:00
Adrià Franch e5c6099285 test(agc): run the pipeline cache test in ctest 2026-10-10 01:06:10 +02:00
MarcZX100 cf043ca665 test(agc-driver): check explicit flush for untracked refresh
Untracked host imports may retain pending image results on the GPU after an unchanged refresh. Assert that behavior and verify that an explicit FlushPending makes the results visible in guest memory, while watched memory still checks refresh write-back.

Fixes #2155
2026-10-09 23:04:37 +00:00
darhebkf d440111bee fix(tools): publish NID database cache after download completes 2026-10-10 01:04:19 +02:00
TibixDev e272161605 perf(pipeline): reuse lookup storage and hash keys in blocks
Keep serialized lookup scratch under the existing pipeline cache mutex and use the standard byte-string hash for indexing. Preserve exact key comparison and private handling of unidentified shaders. Add a real-device cache lifetime fixture and warmed lookup benchmark.

Written with AI assistance.
2026-10-10 01:03:16 +02:00
MarcZX100 10957e0dc4 docs(build): show Fedora static package command 2026-10-09 23:03:15 +00:00
MarcZX100 6074d658f8 docs(build): note Fedora static link packages 2026-10-09 23:03:15 +00:00
MarcZX100 8af7d99720 test(libc): use guest ABI in file stream test 2026-10-09 23:02:29 +00:00
MarcZX100 46b2dfab20 test(libc): avoid undefined read-only fwrite in stream test 2026-10-09 23:02:29 +00:00
MarcZX100 1374a30a2b test(libc): register file stream coverage 2026-10-09 23:02:29 +00:00
Adrià Franch 8868d563b5 test(relinker): make guest_module_args run its native path
The machine check compared against 'x86-64' (uname reports 'x86_64'), so the
native execution was always skipped. With it enabled the fixture itself was
wrong: the initialiser's rip-relative call used the wrong displacement, and
the pending block was set on a different copy of the host library than the
one the module binds to.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 00:57:52 +02:00
jeffrey12cali 7d1821e3ab fix(relinker): emit the relocation table when the guest module has none
The DT_RELA tags were still guarded on the input module's relocation table, while the
new accessor relocations were appended to a copy of it. A module with an initialiser and
no imports therefore kept the argument stub but lost both relocations that fill its GOT
slots, so the stub called through a null pointer at load time.

Guard on the extended table instead, and drop the unused start parameter from the
displacement helper. The test now converts a module whose DT_RELASZ is zero and asserts
that the output carries both accessor imports and a 48-byte relocation table.
2026-10-10 00:57:52 +02:00
jeffrey12cali 7b8b2047b8 test(relinker): assert converted modules receive the module argument block
Add a hand-built guest module with an explicit DT_INIT that forwards rdi and rsi to a
host recorder without touching them and returns a known value. The test sets a known
argument count and argument pointer, loads the converted module, and asserts that the
initialiser received both values and that the stub forwarded its return value.

The host recorder also provides the two accessor symbols, so the test resolves them
without loading libkernel. The converted module must import both accessors, which is
what distinguishes the new behaviour from the previous stub that zeroed the arguments.
2026-10-10 00:57:52 +02:00
jeffrey12cali 36c979b369 fix(libkernel): pass module args and argp to runtime-loaded modules on Linux
sceKernelLoadStartModule discarded its arguments, and the relinker's Linux guest writer
synthesized an initialisation trampoline that also cleared the argument registers before
jumping to the module entry point, so a converted module always reached its own start-up
code with args = 0 and argp = NULL.

On PPSA28997 two of the title's own modules validate that parameter block as their first
act and dereference it unconditionally: SaveData faults on `mov (%rsi),%eax` with rsi = 0
beside its `cmp $0x10` size checks, and PSN faults the same way at PSN+0x3ee7 with rbx = 0.
The Windows branch delivers the block, so identical code reports its parameter-version
error and continues instead of faulting.

sceKernelLoadStartModule now records the pair before dlopen and clears it afterwards, and
the emitted DT_INIT stub reads it through two accessors exported by libkernel. The
initialiser is called rather than tail-jumped so its return value can be reported through
*res as the PS5 API specifies. The state is thread_local, which makes the handoff per-call:
ld.so runs a module's initialiser on the thread that called dlopen. DT_FINI keeps a plain
call-through, so unloading neither reads stale arguments nor reports a result.

The accessor names use the _nid_no_patch suffix so the NID resolver leaves them alone and a
guest import can name them exactly.
2026-10-10 00:57:51 +02:00
Adrià 0df342c640
Merge pull request #1179 from MichonGoddijn231849/feat/pixel-ancillary-whole-word
feat(recompiler): pixel ancillary word used whole
2026-10-10 00:56:51 +02:00
Adrià dc4b7104e5
Merge pull request #2205 from XairRrR/feat/gamelivestreaming-status2
feat(libs): implement sceGameLiveStreamingGetCurrentStatus2
2026-10-10 00:55:16 +02:00
virp-mta 95cd0e8faf feat(libScePad): implement scePadSetAngularVelocityBiasCorrectionState 2026-10-10 02:54:42 +04:00
Adrià c2f1139436
Merge pull request #1824 from Mouhand-Kaddo/feat/sce-zlib
feat(zlib): implement sequential libSceZlib decompression
2026-10-10 00:54:10 +02:00
Adrià Franch 0e32f3662b fix(memory): throw when the direct memory write view cannot be mapped 2026-10-10 00:53:38 +02:00
TibixDev e7f4b1a1fd perf(memory): write tracked direct memory through backing views
Retain host backing views for emulator writes and completion labels. Validate full spans, preserve write versions and GPU ordering, and keep the fallback for other mappings. Test remaps, aliases, access checks, partial failures, tracking, view lifetime, and completion ordering.

Written with AI assistance.
2026-10-10 00:53:29 +02:00
TibixDev 2d1031b7b9 test(ngs2): cover append boundaries and missing waveform metadata 2026-10-10 00:50:24 +02:00
TibixDev 4a04a78bfc fix(ngs2): decode ATRAC9 across streamed waveform blocks
Keep logical sample and skip counts across byte-only continuation buffers, assemble split superframes, and allow callbacks to refill, pause or reset the stream. Preserve decoded audio while waiting for input and reject truncated closed streams.

Validated with seven NGS2 tests, an ASan/UBSan streaming test build, and PPSA03747 repeatedly supplying continuation buffers during playback. Flag semantics follow the pinned KytyPS5 source documented in TechnicalDebt.md.

Written with AI assistance.
2026-10-10 00:50:23 +02:00
Celegans12 a3ca03e057 fix(videoout): remove duplicate VRR exports
The named VRR functions hash to LibwuIonIBw and kP2L8t3j-aM already.
Their explicit aliases therefore create second PE exports with the same
patched NIDs and prevent Windows builds from completing.

Keep the named function exports and remove their redundant aliases.
The NID patcher's duplicate-export validation remains unchanged.
2026-10-10 00:49:47 +02:00
TibixDev 1a0c999ac0 perf(memory): reduce repeated write-tracking range scans
Scan version stamps within contiguous leaves. On Linux, collect nearby
pages within queue epochs only after confirming full watched coverage.
Keep the requested range on Windows. Select the range before collection
and do not retry a failed walk.

Test sparse-leaf boundaries, write histories, partial unwatches and epochs.
Fedora 44 Release tests pass with default, disabled and shared caching.
Isolated upstream comparison reduces the saved collect replay by 11-12%.
Windows was not tested.

AI-assisted: yes.
2026-10-10 00:49:13 +02:00
Adrià c9d42619a6
Merge pull request #1292 from Celegans12/feat/agc-draw-null-srt
feat(agc): implement deferred faults for descriptors read through null SRT pointers
2026-10-10 00:48:27 +02:00
Adrià dfa8b4338f
Merge pull request #1274 from CnRJay/fix/recompiler-descriptor-phi-web
fix(recompiler): split image reads whose descriptor is a web of SRT Phis
2026-10-10 00:44:00 +02:00
MarcZX100 622984257b test(agc): pin serialized user data size 2026-10-09 22:43:42 +00:00
MarcZX100 50f1f1aa84 fix(agc): read shader user data without tail padding 2026-10-09 22:43:42 +00:00
Adrià 5c26edf5dc
Merge pull request #1267 from Celegans12/perf/shader-bda-span-reads
perf(shader): share the BDA dword span read between read sites
2026-10-10 00:43:40 +02:00
authurtabo-byte 035b675e6d fix(libkernel): initialize the full local-time conversion state 2026-10-09 15:43:24 -07:00
Adrià Franch ab658fcfb0 docs(technical-debt): state what raise does for each recorded signal 2026-10-09 23:42:52 +01:00
john.maia e462d0602a refactor(libkernel): size the delivered signal handler table like the dispositions
Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
2026-10-09 23:42:43 +01:00
john.maia cfe4a277c4 feat(libkernel): implement sigaction
EVO-PLAYER (PPSA99039) v0.11.0 stops at sigaction once its earlier
imports resolve: it installs a crash handler for SIGSEGV, SIGBUS and
SIGABRT and a quit handler for SIGTERM, SIGINT and SIGHUP at start-up.

sigaction records the handler, flags and mask of signals 1 to 128 and
reports them back, with FreeBSD's EINVAL cases. signal shares the table
and records SA_RESTART, as FreeBSD's libc does. Plain handlers on the
signals signal already delivers run as signal handlers do; SA_SIGINFO
handlers and other signals are recorded only, and raise of such a
signal throws.

Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
2026-10-09 23:42:43 +01:00
Adrià cb9734cd8a
Merge pull request #1272 from Dextroid17/fix/relinker-dynamic-table-bounds
fix(relinker): bound the symbol and relocation table reads
2026-10-10 00:42:33 +02:00
john.maia e4dcf3e6c0 fix(relinker): end the guest frame-pointer chain at the entry stub
The entry stubs called the title's entry with rbp left as the process
started it (0 on Linux) or as a loop counter left it (0 on Windows). The
title's start code pushes rbp, so the frame-pointer chain of its main
thread ended in a null frame pointer. Unreal Engine walks that chain to
capture call stacks (for an ensure, for example) and reads the return
address at [rbp + 8], so the walk read address 8 and crashed.

Both stubs now push a zero frame record (saved rbp 0, return address 0)
and point rbp at it before the call, so frame-pointer walks stop at the
entry. The Linux stub pushes it below the aligned stack pointer, keeping
the 16-byte alignment at the call. The Windows stub writes it into free
slots of its own frame at rsp+0x40.

PPSA15657 crashed in its stack walk at the title screen in about half of
its runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134RWCyiyydJBbfKz8g9Bwe
2026-10-09 23:42:31 +01:00
john.maia f70d2bdf87 fix(agc): name the reason when /dev/udmabuf cannot be opened
On Linux, shared direct memory is imported through /dev/udmabuf (#943).
Many distributions create it as root:kvm 0660, so a user outside the
kvm group cannot open it. The ranges are then copied instead of
imported, and GPU stores through FLAT/GLOBAL addresses to them fail
with "BDA access failed": DOOM PPSA99666's compute presenter falls back
to its CPU scaler. The only trace was "failed at open /dev/udmabuf
(-1000072003)", a Vulkan result that hides errno.

Print the open error once, with the fix for EACCES, and document the
requirement in USAGE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:42:31 +01:00
authurtabo-byte 9c292fd939 fix(shader): reserve heap space for sixteen sampler pairs 2026-10-09 15:40:51 -07:00
Adrià 464203cea8
Merge pull request #1265 from popcoder565/perf/bda-store-byte-loop
perf(recompiler): loop the BDA byte stores and written-page probes
2026-10-10 00:40:50 +02:00
Dean 3e3290dc03
Merge pull request #2360 from Aerovity/ci/labels-skip-existing
ci(labels): create unforced labels only when they are missing
2026-10-10 11:39:22 +13:00
Adrià a00165da9e
Merge pull request #1252 from MathiasDevelopes/feat/recompiler-native-f16-rte
feat(recompiler): convert f32 to f16 natively when the device rounds 16-bit floats to nearest even
2026-10-10 00:39:15 +02:00
MarcZX100 89661f8f5d test(agc): isolate optional geometry register cases 2026-10-09 22:38:09 +00:00
MarcZX100 f8c237b1ac test(agc): cover missing hull output register 2026-10-09 22:38:09 +00:00
MarcZX100 e94f0c8f63 test(agc): verify optional geometry output register 2026-10-09 22:38:09 +00:00
MarcZX100 35c0baef20 fix(agc): accept unused geometry output register 2026-10-09 22:38:09 +00:00
Adrià Franch e4a911fcd3 test(agc): use raw buffer descriptors in the v_fma_f64 subnormal test
With OOB_SELECT 0 and stride 0 every access is out of range now that the
buffer bounds follow OOB_SELECT, so the shader never read or wrote.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 00:38:04 +02:00
Adrià Franch b2961b702c docs(debt): v_fma_f64 subnormals measured, f64 denormal flush not read
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 00:38:04 +02:00
Adrià Franch 1dcdca1498 test(agc): pin v_div_fmas_f64 with VCC set on subnormal operands and results
Expected values measured on RDNA2 (gfx1035) with the HW oracle at IEEE=0
and IEEE=1, f64 denormals kept.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 00:38:04 +02:00
Nahuel Genchi a12ddaa905 fix(shader): round v_fma_f64 once for subnormal operands and results
A subnormal operand sent v_fma_f64 to a separate multiply and add, and a
subnormal result was rounded twice: once to 53 bits in the scaled domain
and again by the power-of-two rescale. Both differ from IEEE 754
fusedMultiplyAdd in the last bit.

Subnormal operands are now widened by 2^64 and enter the exact path with
their exponent lowered by 64. The exact path keeps the sign of the residual
between the 53-bit result and the exact sum; when the result lands on a
midpoint of the subnormal grid it is moved one ulp towards the exact sum
before the single final rounding. Normal results are rebuilt by setting
the exponent, so only a subnormal result rounds. v_div_fmas_f64 shares the
path.
2026-10-10 00:38:04 +02:00
Adrià 3692f56f09
Merge pull request #1249 from Raghav314/fix/relinker-guest-hash
fix(relinker): write a bucketed hash table for Linux guest modules
2026-10-10 00:37:47 +02:00
Dean 4623971a17
Merge pull request #2244 from swagdotsh/fix-agc-visual-demo
fix(agc): restore the standalone visual demo
2026-10-10 11:37:00 +13:00
Dean 860b82600a
Merge pull request #1369 from MarcZX100/test/getcwd-zero-buffer-einval
test(libc): cover getcwd zero-size buffer
2026-10-10 11:36:50 +13:00
MarcZX100 38baacad0c fix(tools): write overlap reports as UTF-8 2026-10-09 22:36:26 +00:00
Adrià e66180f1bb
Merge pull request #1972 from babyhuey/feat/libc-inet-addr
feat(libc): implement __inet_addr
2026-10-10 00:35:34 +02:00
Adrià 09a3462eca
Merge pull request #1192 from ps54all/feat/libkernel-posix-rename
feat(libkernel): export the POSIX rename
2026-10-10 00:34:32 +02:00
Dean 8fd2f4c412
Merge pull request #1778 from MarcZX100/codex/docs-fork-workflow-approval
docs(contributing): document CLI for manual Build runs
2026-10-10 11:33:25 +13:00
Dean 96ce3acdd0
Merge pull request #1028 from Dextroid17/ci/guard-against-new-skips
ci: fail when a test skips that the job's device is not expected to skip
2026-10-10 11:33:15 +13:00
Adrià 27965d8ae7
Merge pull request #1170 from MichonGoddijn231849/fix/dcc-keys-fill-over-aliased-images
fix(agc): a fill of a surface's DCC keys is a key fill over other images' memory
2026-10-10 00:32:43 +02:00
esatturan 9c95d4810e fix(ajm): decode an ATRAC9 run's whole input and follow gapless segments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:29:58 +03:00
Adrià c6e3aa767b
Merge pull request #1146 from alfalfa-star/perf/agc-draw-snapshot-budget
perf(agc): keep draw snapshots of storage buffers up to 1 GiB
2026-10-10 00:25:31 +02:00
Joey Fisher 6b41cf4dbf fix(shader): lower the packed pixel ancillary extracts when a masked copy blocks the whole word 2026-10-09 16:25:28 -06:00
Raihan Abdul Majid e768d97949 fix(kernel): keep the file offset in Windows AIO reads and writes
Each Windows AIO request is an overlapped ReadFile/WriteFile at the
request's offset, which on a synchronous handle also moves the
descriptor's file pointer; on the console AIO transfers leave it alone.
The requests now go through the positioned path sceKernelPread and
sceKernelPwrite use (NativePositioned in Stdio.cpp, exposed as
NativePositioned_nid_no_patch), which restores the pointer afterwards.
Negative offsets still fail with EINVAL before the transfer.

GuestAio sets the offset to 2 before a write batch and checks it is
still 2 after. TechnicalDebt records that a concurrent read or write on
the same descriptor can see the moved pointer in between, as for the
pread family.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
2026-10-10 00:22:22 +02:00
Adam Stachowicz 95073bc45a ci(release): match PR CI Vulkan and Windows SSL setup
Install lavapipe on Linux release builds and set ANYPS5_REQUIRE_VULKAN and GALLIUM_OVERRIDE_CPU_CAPS for ctest so GPU execution tests run instead of skipping. Scope SSL_CERT_FILE to Windows winlibs download and CMake configure steps only so Linux FFmpeg fetch is not broken. Leave release ctest as a single strict run.
2026-10-10 00:20:59 +02:00
Adrià 64fe743995
Merge pull request #1080 from alfalfa-star/feat/videoout-window-icon
feat(videoout): use sce_sys/icon0.png as the window icon
2026-10-10 00:16:44 +02:00
Adrià fc063cff85
Merge pull request #1074 from alfalfa-star/feat/agc-graphics-int64-atomics
feat(agc): accept 64-bit atomics in graphics shaders when the device enables them
2026-10-10 00:14:56 +02:00
Adrià a0d96ac0b4
Merge pull request #552 from Pouare514/feat/stubgen-tool
feat(tools): generate Export.cpp skeletons from missing NIDs
2026-10-10 00:14:40 +02:00
Adrià 2d537f13bb
Merge pull request #1073 from alfalfa-star/feat/agc-uint16-color-export
feat(agc): accept UINT16_ABGR color exports into unsigned integer targets
2026-10-10 00:13:23 +02:00
Adrià fa899a3468
Merge pull request #1857 from hikazey/feat/msync
feat(libkernel): implement msync
2026-10-10 00:12:20 +02:00
Saranxzi e06c459534 test(libkernel): cover virtual query after partial unmap
Carry over the direct mmap regression from PR #2267. The live-extent implementation is already present in the preceding commits.
2026-10-09 22:11:35 +00:00
Michon d8b1ad71d8 fix(recompiler): lower the ancillary word only where every reader extracts a modelled field
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 00:11:23 +02:00
Michon 9905f5ddd7 feat(recompiler): pixel ancillary word used whole
A use of the packed ancillary VGPR other than a constant field extract (the word passed through a
select before its sample number is extracted) reads the word rebuilt from the sample number (bit 8)
and the render target index (bit 16). Extracts of other bits straight from the word stay refused, and
the refusal now names the uses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 00:11:13 +02:00
MarcZX100 eb1e6b22a9 test(libkernel): assert virtual query lease ordering 2026-10-09 22:10:33 +00:00
MarcZX100 f7de40f9bb fix(libkernel): query non-readable live guest ranges 2026-10-09 22:10:33 +00:00
Praveen Kumar 6f62ec6a6f fix(libkernel): query current guest mapping extents
Use the current registered range after protection splits and partial unmaps, including FIND_NEXT lookups. Add a regression covering extents, protection and surviving contents.

AI-assisted: yes
2026-10-09 22:10:32 +00:00
Adrià e51d4e1f21
Merge pull request #1812 from journaltraces/feat/libc-stpcpy
feat(libc): implement stpcpy
2026-10-10 00:08:33 +02:00
Adrià ec05c02205
Merge pull request #1713 from MathiasDevelopes/feat/libsceime-panel-position-and-form
feat(libSceIme): implement sceImeGetPanelPositionAndForm
2026-10-10 00:08:14 +02:00
popcoder565 5dc7021c38 Merge remote-tracking branch 'origin/main' into fix/kernel-raise-exception-ntcontinue
Keeps both new TechnicalDebt entries: this branch's note that a raise
can still reenter host code it interrupted, and #2107's sigaltstack note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 18:07:20 -04:00
Dean b2714175b4
Merge pull request #2227 from rmz-24/test/relinker-gui-fixtures-without-wer
test(relinker): launch the GUI startup fixtures without Windows Error Reporting
2026-10-10 11:06:52 +13:00
Adrià 025a911360
Merge pull request #2359 from mrzacarias/feat/rudp-get-status
feat(libSceRudp): implement sceRudpGetStatus
2026-10-10 00:04:52 +02:00
MarcZX100 02005c86d2 fix(agc): detect narrow clock on RX 7800 XT 2026-10-09 22:04:49 +00:00
Adrià Franch 810eda2edf docs(zlib): record shadPS4 length and invalid-argument differences
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 02:03:59 +04:00
Mouhand Kaddo 9f55bf71b7 fix(zlib): inherit DWARF unwinding in Windows tests 2026-10-10 02:03:59 +04:00
Mouhand-Kaddo f0cec39265 fix(zlib): inherit MinGW unwind mode for SysV exports
Remove the asynchronous unwind override so SysV exports use the project DWARF unwinding and avoid invalid SEH assembler directives.
2026-10-10 02:03:59 +04:00
Mouhand-Kaddo 8fc83ae05c feat(zlib): implement sequential libSceZlib decompression
Resolve the missing system library with checksum-validating decompression. Add behavioral tests and document unsupported request semantics.
2026-10-10 02:03:59 +04:00
Adrià 0ccdf15f18
Merge pull request #915 from Pacuka/fix/audiodec-m4aac-raw-channels
fix(audiodec): take the M4AAC raw channel layout from the stream
2026-10-10 00:03:46 +02:00
Adrià bfef67f362
Merge pull request #1849 from authurtabo-byte/fix/audio3d-missing-exports
feat(libSceAudio3d): implement sceAudio3dObjectSetAttributes and sceAudio3dPortFlush
2026-10-10 00:03:08 +02:00
Adrià 593001d8fd
Merge pull request #1818 from journaltraces/feat/libc-ldiv
feat(libc): implement ldiv
2026-10-10 00:02:42 +02:00
Adrià b0d834be25
Merge pull request #1796 from Mouhand-Kaddo/feat/posix-gethostbyname
feat(posix): implement gethostbyname
2026-10-10 00:02:15 +02:00
MarcZX100 aa17030a65 fix(agc): detect AMD proprietary narrow clock on RX 7900 XT 2026-10-09 22:02:13 +00:00
MarcZX100 0f1f5e721b fix(agc): detect narrow clock on tested AMD device 2026-10-09 22:02:13 +00:00
Adrià c2ac5dd93f
Merge pull request #1676 from Recapi/feat/libkernel-thread-cpu-clock
feat(libkernel): implement pthread_getcpuclockid and per-thread CPU clocks
2026-10-10 00:01:18 +02:00
Adrià 6642559456
Merge pull request #1675 from Recapi/feat/libkernel-getrlimit
feat(libkernel): implement getrlimit for RLIMIT_DATA
2026-10-10 00:00:57 +02:00
Hannah Lyons 128d2e81dc test(libc): pin __inet_addr to FreeBSD one-part wrap 2026-10-10 00:00:38 +02:00
Hannah Lyons 11e058654d feat(libc): implement __inet_addr 2026-10-10 00:00:38 +02:00
Adrià fff9bd3185
Merge pull request #851 from meh7an/perf/agc-pm4-queue-reset-stack
perf(agc): reset the PM4 queue state without a 48 KiB stack temporary
2026-10-10 00:00:22 +02:00
Dean 9ee4972db6
Merge pull request #2336 from JAB-dev/feat/ngs2-reverb-rack
feat(libSceNgs2.native): reverb rack following the PS4 libSceNgs2 reverb
2026-10-10 10:59:54 +13:00
Adrià c0753c7d40
Merge pull request #856 from meh7an/perf/agc-shadow-overlap-without-copies
perf(agc): query unit shadows without copying the overlap list
2026-10-09 23:59:52 +02:00
Adrià 2a42045df8
Merge pull request #2153 from EdouardSence/feat/ult-ulthread-runtime
feat(libSceUlt): implement sceUltUlthreadTryJoin, sceUltUlthreadRuntimeDestroy and the underscore ulthread exports
2026-10-09 23:59:50 +02:00
Adrià 416e40ef29
Merge pull request #2118 from rozbh/feat/libkernel-aio-poll-requests
feat(libkernel): implement sceKernelAioPollRequests
2026-10-09 23:59:29 +02:00
Adrià befbf64c13
Merge pull request #2039 from Aryansh1520/feat/libc-malloc-stats-fast
feat(libc): implement malloc_stats_fast through the application allocator
2026-10-09 23:58:30 +02:00
Jan Šlégl 9d0b105771 fix(libkernel): read and write guest sockets
read, write, _read and _write on a guest socket descriptor went to the
host, which has no such descriptor, so sceKernelRead and sceKernelWrite
threw. They now reach the socket as recv and send without flags, with
the socket layer's errno (EAGAIN 35, EPIPE 32, EBADF 9), a zero-length
read returns 0 as dofileread does, and the two sceKernel forms return
the kernel error for the same cases. The host's SIGPIPE on EPIPE, a
write above INT_MAX bytes, readv, writev and the positioned forms are
recorded in TechnicalDebt.

OpenSSL's QUIC notifier signals its socketpair with write and read.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 23:57:33 +02:00
XairRrR c642428e82 feat(libs): implement sceGameLiveStreamingGetCurrentStatus2
The status layout is shadPS4's OrbisGameLiveStreamingStatus2 (72
bytes). Live streaming is not supported, so the call reports that no
stream is on air, with an invalid user id; a null status throws.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at sceGameLiveStreamingGetCurrentStatus2.
2026-10-09 23:56:40 +02:00
Adrià 7331a123e9
Merge pull request #2107 from LeandroLP23/feat/libkernel-sigaltstack
feat(libkernel): implement sigaltstack
2026-10-09 23:56:02 +02:00
Adrià db06355f84
Merge pull request #1859 from overlordxrz-source/feat/libkernel-system
feat(libkernel): implement system
2026-10-09 23:55:09 +02:00
Adrià 7b705629a6
Merge pull request #1714 from johnmaia/feat/videoout-resolution-status
feat(videoout): implement sceVideoOutGetResolutionStatus
2026-10-09 23:54:46 +02:00
Adrià aad16d0577
Merge pull request #1848 from LeandroLP23/feat/libc-inet-aton
feat(libc): implement __inet_aton
2026-10-09 23:53:56 +02:00
Adrià cb4f41c1e8
Merge pull request #1978 from LuisBiceps/feat/agc-get-tf-ring
feat(agc): implement sceAgcDriverGetTFRing
2026-10-09 23:53:52 +02:00
Adrià e2713aad70
Merge pull request #1987 from babyhuey/feat/libc-fpclassifyf
feat(libc): implement __fpclassifyf
2026-10-09 23:53:48 +02:00
Gjon Gojcevic 21f94288ac fix(shader): mark the vertex position output invariant
Two different vertex programs that compute the same position give
bit-identical depth on the GPU, which a depth pre-pass followed by an
equal-or-greater redraw relies on. Without Invariant, a Vulkan driver may
compile the same position arithmetic differently in each shader (for
example contracting into an FMA in only one), so the redraw fails the
depth test.

Decorate the gl_PerVertex Position member and the mesh shader's Position
output Invariant, and check both in a new recompiler test.

AI-assisted: yes
2026-10-09 17:53:07 -04:00
Adrià 8d47cfba88
Merge pull request #1807 from SleglJan/feat/libkernel-sandbox-random-word
feat(libkernel): implement sceKernelGetFsSandboxRandomWord
2026-10-09 23:52:40 +02:00
Adrià 5d0b955642
Merge pull request #1627 from babyhuey/feat/libkernel_sys-readlink
feat(libkernel_sys): implement readlink
2026-10-09 23:52:37 +02:00
Adrià 72cf6c3c5a
Merge pull request #1624 from babyhuey/feat/libkernel-lstat
feat(libkernel): implement lstat
2026-10-09 23:52:02 +02:00
Adrià 2dbc137693
Merge pull request #1798 from hugodearaujo/feat/libkernel-pthread-getname-np
feat(libkernel): implement pthread_getname_np
2026-10-09 23:51:56 +02:00
Adrià 4b112364b5
Merge pull request #1339 from gjonn/feat/videoout-vrr-status-event
feat(libSceVideoOut): register the VRR status event and accept the VRR status call
2026-10-09 23:51:35 +02:00
Dean 4cdf38439a
Merge pull request #2334 from parl0v/docs/drop-stale-pool-stats-debt
docs: drop the stale unknown-signature entries for the memory pool stats
2026-10-10 10:51:07 +13:00
Adrià 830130aa00
Merge pull request #1620 from babyhuey/feat/libkernel-fdatasync
feat(libkernel): implement fdatasync
2026-10-09 23:50:45 +02:00
Dean 330cfae722
Merge pull request #2176 from oneandonlydean/up639/adjusted-regions
perf(agc): bind misaligned draw buffer regions in place through the view adjustment
2026-10-10 10:49:12 +13:00
Adrià 3d19932caf
Merge pull request #1738 from SleglJan/feat/libkernel-termios
feat(libkernel): implement tcgetattr and tcsetattr
2026-10-09 23:48:53 +02:00
Adrià 64c6b11420
Merge pull request #1729 from johnmaia/feat/libc-syslog
feat(libc): implement syslog and vsyslog
2026-10-09 23:48:32 +02:00
Dean 19a0daa786
Merge pull request #2295 from parl0v/test/sce-net-reset-on-unread-close
test(net): reset the closed peer with unread data so the send fails at once
2026-10-10 10:47:13 +13:00
Dean 6cc3c9c5e2
Merge pull request #2286 from eljackjoestar-cmd/codex/pr-rtc-timezone-bounds
fix(rtc): validate ticks before timezone conversion
2026-10-10 10:47:03 +13:00
Dean 292d854ea6
Merge pull request #2264 from xXPBSXx/docs/build-windows-antivirus
docs(build): note antivirus quarantine of relinker test executables on Windows
2026-10-10 10:46:53 +13:00
Dean dcb3180691
Merge pull request #2251 from zmeizy/claude/sce-net-without-ipv6
test(net): skip only the IPv6 socket checks on a host without IPv6
2026-10-10 10:46:43 +13:00
Dean 2b62214acc
Merge pull request #2250 from PrintOrb/fix/progress-windows-utf8
fix(tools): preserve UTF-8 in progress comparisons
2026-10-10 10:46:33 +13:00
Dean 0d3b7118a1
Merge pull request #2240 from orbz22/fix/patched-libraries-no-error-dialog
test(libs): report patched libraries that fail to load instead of a loader dialog
2026-10-10 10:46:22 +13:00
Dean 173adda9d8
Merge pull request #2210 from Rohan03x/fix/freetype-rc-path
build: skip the FreeType version resource so Windows builds work in paths with spaces
2026-10-10 10:46:12 +13:00
Dean a4e0889b5d
Merge pull request #2209 from Rohan03x/docs/windows-runtime-dlls
docs(usage): list the MinGW runtime DLLs a self-built libs directory needs
2026-10-10 10:46:02 +13:00
Dean 131a784c07
Merge pull request #2194 from AchrafReyani/build/guard-nominmax-kernel-sync
build(windows): guard NOMINMAX in the kernel sync test
2026-10-10 10:45:51 +13:00
Dean 879874aedd
Merge pull request #2098 from treuenten/fix/tools-import-audit-exit-two
fix(tools): exit 2 when import_audit cannot read an input or write --json
2026-10-10 10:45:32 +13:00
Dean 31cf52d587
Merge pull request #2027 from kali113/fix/storage-cache-test-runtime
test(agc): bound the storage cache budget regression workload
2026-10-10 10:45:22 +13:00
Dean f67c9e4084
Merge pull request #1358 from MarcZX100/test/register-guest-hmd
test(hmd): register disconnected-device tests
2026-10-10 10:45:11 +13:00
Dean 80cc71419b
Merge pull request #1355 from MarcZX100/test/register-pthread-start
test(libkernel): register and bound pthread start test
2026-10-10 10:45:00 +13:00
Dean 8908c3ee18
Merge pull request #2350 from snoozedDev/feat/hw-oracle-lds-size
feat(hw-oracle): make the group segment size an option
2026-10-10 10:44:34 +13:00
Dean 75994ad8ec
Merge pull request #2337 from JAB-dev/fix/ngs2-matrix-level-clamp
fix(libSceNgs2.native): clamp matrix levels to -4..4 as the PS4 libSceNgs2 does
2026-10-10 10:44:24 +13:00
Dean 0856926cc3
Merge pull request #2299 from popcoder565/test/agc-unit-shadow-import-retire
test(agc-driver): retire the unit shadow block's import before releasing it
2026-10-10 10:44:14 +13:00
Dean 6918141ebe
Merge pull request #2249 from zmeizy/claude/llvmpipe-shader-clock-wrap
test(agc): compare llvmpipe shader clocks modulo 2^32
2026-10-10 10:44:04 +13:00
Dean 05963a68b8
Merge pull request #2175 from oneandonlydean/up639/pipeline-cache-bound
perf(agc): keep up to 1024 cached pipelines
2026-10-10 10:43:53 +13:00
Dean 8d73b5d49f
Merge pull request #2163 from Zheorgyan/fix/ajm-at9-synthetic-fill
test(ajm): use a synthetic AT9 block that stays inside the gradient table
2026-10-10 10:43:43 +13:00
Dean cb86a0f269
Merge pull request #2159 from Angel21PC/fix/avplayer-ps5-init-data-ex
fix(avplayer): read the PS5 SceAvPlayerInitDataEx layout
2026-10-10 10:43:32 +13:00
Dean 8d946685b5
Merge pull request #2131 from authurtabo-byte/fix/save-memory-32-mib
fix(libSceSaveData): accept 32 MiB save memory
2026-10-10 10:43:21 +13:00
Dean 2290e1ab83
Merge pull request #2130 from authurtabo-byte/fix/audio-out-state-query-waits
fix(libSceAudioOut): allow state queries during output waits
2026-10-10 10:43:10 +13:00
Dean 4324dcd9a5
Merge pull request #2122 from Negesin/fix/buffer-unaligned-int64-skip
test(agc): skip unsupported int64 atomic subcase
2026-10-10 10:43:00 +13:00
Dean 51b1c56057
Merge pull request #2065 from LuisBiceps/feat/system-service-web-browser-unavailable
feat(libSceSystemService): report the web browser as unavailable
2026-10-10 10:42:50 +13:00
Dean da122c90ff
Merge pull request #1986 from kali113/fix/shader-cache-test-cleanup
test(agc): flush shader cache writes before removing test files
2026-10-10 10:42:39 +13:00
Dean 103c315f70
Merge pull request #1741 from SleglJan/fix/tools-pr-overlap-declarations
fix(tools): count only definitions as exports in the overlap report
2026-10-10 10:42:27 +13:00
Dean 6882143a80
Merge pull request #1325 from darhebkf/codex/fix-overlap-pagination
fix(tools): check overlap against every open pull request
2026-10-10 10:42:13 +13:00
Dean 1f79a92a72
Merge pull request #1323 from darhebkf/codex/fix-conventions-line-comments
fix(tools): preserve function bodies after line comments
2026-10-10 10:42:03 +13:00
hikazey 0bff6da3d3 feat(libkernel): implement msync
msync follows FreeBSD 11's kern_msync and vm_map_sync over the guest's
mappings as sceKernelVirtualQuery reports them: the address is rounded
down to the page, a range that wraps and MS_ASYNC with MS_INVALIDATE are
EINVAL, an unmapped start or page is ENOMEM, and length 0 checks the
mapping that holds the address. The guest has no file mappings, so a
successful call has nothing to write back. MS_INVALIDATE on a mapped
range throws, since FreeBSD's EBUSY for mlocked pages needs lock state
that is not tracked.

EVO-PLAYER PPSA99039 v0.11.0 imports it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:38:58 +02:00
Adrià e603f3f560
Merge pull request #1613 from NumberGuan/codex/posix-temp-files
feat(posix): implement mkstemp and isatty
2026-10-09 23:37:02 +02:00
Adrià Franch 4dfeac2989 docs(technical-debt): move the sceImeGetPanelPositionAndForm entry off the end of its section
Lines at the end of a section conflict with every other pull request that appends there.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-09 23:36:36 +02:00
MathiasDevelopes e21d8bd12f feat(libSceIme): implement sceImeGetPanelPositionAndForm
The IME panel cannot be open while sceImeOpen is unimplemented, so the
query returns SCE_IME_ERROR_NOT_OPENED and leaves the output untouched,
like sceImeSetCaret, sceImeSetText and sceImeSetTextGeometry. As with
sceImeSetCaret, the closed panel is reported before a null output.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 23:36:28 +02:00
Adrià 00159cffb5
Merge pull request #1544 from arvindfroi/feat/share-remaining-calls
feat(share): answer sceShareSetContentParamForApplicationTitle
2026-10-09 23:34:10 +02:00
Claude 2243e17f34
fix(libc): return a 64-bit unsigned long from _Stoul on Windows
The guest's unsigned long is 64 bits. _Stoul was declared with the
host's unsigned long and returned std::strtoul, which are 32 bits on
Windows (LLP64): "4294967296" clamped to 4294967295 with ERANGE and
"-1" gave 0xffffffff, so a guest std::stoul threw out_of_range on values
the console accepts. It now returns std::uint64_t from std::strtoull,
as strtoul_nid_postfix and _Stoull already do; on Linux nothing changes.
The binary-prefix check stays in front of the host call.

Reported in #2424 by AchrafReyani; the same change was proposed in #2442
by SurajKhanna, whose two guest_math cases are taken here. Folded in at
MarcZX100's suggestion on #1459.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 21:33:08 +00:00
Adrià Franch 4924932378 docs(technical-debt): record the unreserved Audio3d object return
shadPS4 returns success for an object id that was never reserved and the invalid-object error only for a released one; this library returns the error for both.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-09 23:33:06 +02:00
authurtabo-byte 57bc8b1661 feat(libSceAudio3d): implement sceAudio3dObjectSetAttributes and sceAudio3dPortFlush
Both exports are imported by titles that link libSceAudio3d; without them the loader fails with an unresolved import before the title runs. Following the offline model, object attributes are validated but produce no audio and PortFlush drops the frames queued by sceAudio3dPortAdvance.
2026-10-09 23:32:52 +02:00
EdouardSence 04dda44d3d feat(libSceUlt): implement sceUltUlthreadTryJoin, sceUltUlthreadRuntimeDestroy and the underscore ulthread exports
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:31:01 +02:00
Hannah Lyons d024717ebe feat(libkernel_sys): implement readlink 2026-10-09 17:30:55 -04:00
Hannah Lyons 903f50a3b4 feat(libkernel): implement lstat 2026-10-09 17:30:43 -04:00
Hannah Lyons 6768210713 feat(libkernel): implement fdatasync 2026-10-09 17:30:24 -04:00
Lexroid 0745d803e5 fix(relinker): fold case when matching needed module stems on Windows
Palworld's eboot needs EOSSDK-PS5-Shipping.debug_prx while the dump ships
prx/eossdk-ps5-shipping.prx. On Windows, compare module stems without
ASCII case, and let a name that already resolves to a guest image (exact
or case-folded filename, or soname) win over a stem alias.

Reported and diagnosed by @Rohan03x in #1830.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:29:45 +03:00
JAB-dev 00e13ecfa7 feat(libSceNgs2.native): implement sceNgs2PanInit and sceNgs2PanGetVolumeMatrix
Pan follows the PS4 firmware 11.00 libSceNgs2.sprx: the speaker layout
from the init angles, then each param's angle and distance into a
volume matrix for the voice. Every param is checked before anything is
written, and angles too large to wrap throw. The pan functions are
exported from the existing Voice.cpp export block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:26:24 +02:00
Claude 8c714f76af
fix(libc): stop the wcstol family at a binary prefix on Linux
wcstol, wcstoll, wcstoul and wcstoull parse the ASCII prefix of the
guest's UTF-16 text with std::strtoll and std::strtoull, which glibc 2.38
and later bind to the C23 __isoc23_* functions: wcstol(u"0b101", &end, 0)
returned 5 with the end pointer after the whole string. They now check
StopAtBinaryPrefix_nid_no_patch first, like the narrow functions, and the
end pointer maps back through ParseAsciiPrefix as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:26:13 +00:00
Claude b5c9945e1f
fix(libc): stop the strtol family at a binary prefix on Linux
C17 has no binary prefix: with base 0 or 2, strtol("0b101", &end, base)
reads the subject "0", returns 0 and leaves end at the 'b'. With glibc
2.38 or later, g++ (which defines _GNU_SOURCE) binds std::strtoll,
strtoull, strtoul, strtoimax and strtoumax to the C23 __isoc23_*
functions, which accept 0b/0B: the Linux exports returned 5 and
consumed the whole string. The Windows UCRT already follows C17, so the
same guest call gave different results on the two hosts.

strtol, strtoul, strtoll, strtoull, _Stoull, strtoimax, strtoumax and
_Stoul now return 0 with the end pointer after the '0' when, after
white space and an optional sign, the text starts with 0b or 0B and a
binary digit, in base 0 or 2. Everything else still goes to the host
function. The scanf family's %i has the same glibc behaviour; it is
recorded in TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:26:13 +00:00
Adrià 54f28f2d31
Merge pull request #1543 from arvindfroi/feat/np-manager-offline-lookups
feat(libSceNpManager): answer sceNpCheckNpAvailability with no user signed in
2026-10-09 23:26:09 +02:00
JAB-dev 9af48b5b02 test(libSceNgs2.native): destroy the system after the unsupported default map render
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:25:40 +02:00
JAB-dev ed9a70175e fix(libSceNgs2.native): mix ports without set levels through the default channel map
A port without a matrix sent source channel n to destination channel n, so a
mono voice reached only the left channel of a stereo mix. The PS4 firmware
11.00 libSceNgs2.sprx mixes such ports, and ports whose matrix levels were
never set, through a fixed channel map instead: mono reaches both stereo
channels at -3 dB and the centre of 5.1 and 7.1, stereo folds to mono at
-3 dB per side, and wider sources fold down with 0.5 and -3 dB gains. The map
was measured for every source width into 1, 2, 6 and 8 channels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:25:31 +02:00
JAB-dev 56d8e5c4df fix(libSceNgs2.native): mix through a selected matrix whose levels were never set
PPSA22520 routes its title music through port matrix 0 without setting the
matrix levels, so the music rendered silent. A matrix without levels now
mixes like a port without a matrix, source channel n to destination channel
n. The console's initial levels are unknown; the assumption is recorded in
TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:25:31 +02:00
Lexroid 1a9ef2f25d fix(relinker): match needed module names that differ only in the extension
A title's executable can name a bundled module differently from the file it
ships: Dying Light 2 needs EOSSDK-PS5-Shipping.debug_prx and ships
EOSSDK-PS5-Shipping.prx. Needed names were matched by exact filename, so the
module was skipped without an error and start-up failed to load it. Renaming
the file does not help either: the title later loads the module at run time
by its shipped name (/app0//EOSSDK-PS5-Shipping.prx), and dlopen looks for
that name's .guest.prx (#1794).

When no file has the needed name, a module whose name differs only in its
.prx, .sprx or .debug_prx extension now satisfies it, in the module
directories or elsewhere under the input. The output keeps the shipped file
name, and the needed name is added as another name of that guest module.
Two such candidates for one needed name are ambiguous, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:24:07 +03:00
Adrià Franch 9d1ac9033e fix(libc): report unknown syslog bits with FreeBSD's internal priority
FreeBSD vsyslog logs the complaint with LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID passed as the priority (0x23), not LOG_ERR.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-09 23:23:49 +02:00
john.maia bcd1b0c2a0 feat(libc): implement syslog and vsyslog
ps5-opengl (PPSA99005) and ProsperoRadio (PPSA99001) import syslog
from libSceLibcInternal. Messages go to stderr with the priority, and
the format follows FreeBSD's vsyslog: %m expansion, masking of unknown
priority bits, LOG_USER as the default facility, errno preserved.

Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:23:42 +02:00
Adrià d724cad38c
Merge pull request #1748 from danielradosa/feat/libkernel-seteuid-setegid
feat(libkernel): implement seteuid and setegid
2026-10-09 23:23:34 +02:00
LeandroLP23 a3f0120da2 feat(libkernel): export environ as an empty environment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:22:58 +02:00
Adrià 5bc7886ab8
Merge pull request #1188 from MathiasDevelopes/feat/kernel-module-info-windows
feat(libkernel): implement sceKernelGetModuleInfoFromAddr on Windows
2026-10-09 23:22:46 +02:00
Adrià 870ac041c5
Merge pull request #1685 from overlordxrz-source/feat/libkernel-sysctl-hw-ncpu
feat(libkernel): implement sysctl and sysctlbyname for hw.ncpu
2026-10-09 23:20:13 +02:00
NumberGuan f9be27619e fix(posix): preserve the socket helper during NID patching 2026-10-09 23:19:03 +02:00
Tomás Ortellado 7a771d2d89 feat(posix): implement mkstemp and isatty 2026-10-09 23:18:58 +02:00
Adrià 2e375a5c84
Merge pull request #1634 from babyhuey/feat/libkernel-getdents
feat(libkernel): implement getdents and getdirentries
2026-10-09 23:18:45 +02:00
Adrià Franch 96418e0396 docs(technical-debt): move the tcgetattr entry into the list 2026-10-09 23:17:19 +02:00
Jan Šlégl 14cc6497d2 feat(libkernel): implement tcgetattr and tcsetattr
A title's descriptors are taken as never being terminals: a file or
pipe gets ENOTTY with the termios untouched, a socket gets what its
protocol answers a termios ioctl on FreeBSD (EADDRNOTAVAIL for AF_INET,
EOPNOTSUPP otherwise), and a closed or invalid descriptor EBADF.
tcsetattr gives EINVAL for an action other than TCSANOW, TCSADRAIN or
TCSAFLUSH, with or without TCSASOFT, before anything else, and EFAULT
for a null termios before the descriptor is checked; with TCSASOFT a
null termios throws, where FreeBSD's libc faults copying it. What the
console gives a title as descriptors 0 to 2 is unknown, as recorded in
TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 23:17:12 +02:00
LeandroLP23 c54143dbb9 feat(libkernel): implement sigaltstack
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:16:18 +02:00
Adrià 87b998a99a
Merge pull request #1673 from SleglJan/feat/libkernel-mlock
feat(libkernel): implement mlock and munlock
2026-10-09 23:15:19 +02:00
mugurc 703989b94b feat(relinker): write Mach-O output for macOS with --macos
The guest image reader and the module builder already produce a
platform-neutral GuestImage; --macos adds a third writer next to the ELF
and PE ones. The executable and every bundled module become x86-64 Mach-O
files (modules as dylibs in app0/sce_module) that run under Rosetta on
Apple silicon.

FreeBSD code reaches its thread pointer through %fs, which macOS cannot
set, so the writer rewrites each %fs access into a stub that reads the
image's thread pointer from a pthread key and allocates the TLS block on
a thread's first access. Dynamic TLS goes through the image's descriptor
instead of __tls_get_addr. Imports bind by NID to the prx libraries
beside the output, exports and TLS imports use the dynamic symbol names,
and the image's metadata lives in __APS5DATA,__meta.

--macos conflicts with --windows. The macOS runtime that consumes the
output (TLS allocation, libraries built for macOS) comes in separate
changes.
2026-10-10 00:13:39 +03:00
Gjon Gojcevic 04dec3ddbc feat(libSceVideoOut): register the VRR status event and accept the VRR status call
LibwuIonIBw registers video out event id 16, which the host never triggers because its VRR state does not change; kP2L8t3j-aM returns 0 without effect.
2026-10-09 23:12:08 +02:00
Adrià 73ba24aacb
Merge pull request #1823 from Mouhand-Kaddo/feat/sce-opus-dec
feat(opus): implement 48 kHz libSceOpusDec
2026-10-09 23:12:02 +02:00
Adrià bbc4438183
Merge pull request #2301 from parl0v/refactor/libc-name-cyber-stubs
refactor(libc): name the 12 Cyberpunk stubs the NID database resolves
2026-10-09 23:07:39 +02:00
Adrià c30b87a25d
Merge pull request #1462 from abderahmane-ai/feat/module-registry
feat(relinker): write a registry for each converted bundled module
2026-10-09 23:06:18 +02:00
Adrià 27cb335be1
Merge pull request #1650 from Pedroj-64/feat/libkernel-uid-gid
feat(libkernel): implement getuid, geteuid, getgid, getegid and issetugid
2026-10-09 23:04:27 +02:00
Adrià 747726c43f
Merge pull request #2203 from XairRrR/feat/libscevdecsw
feat(libs): implement libSceVdecsw on top of libSceVideodec2
2026-10-09 23:04:00 +02:00
Adrià 837dbd8568
Merge pull request #2319 from parl0v/refactor/agc-interpolant-mapping-name
refactor(agc): name HV4j+E0MBHE sceAgcCreateInterpolantMapping_0100
2026-10-09 23:01:34 +02:00
gunerky a58fe0cd72 test(relinker): isolate Windows diagnostic fixtures 2026-10-09 23:59:29 +03:00
Adrià 4c36741929
Merge pull request #1641 from SleglJan/feat/libkernel-sigset
feat(libkernel): implement the sigset functions
2026-10-09 22:58:56 +02:00
Adrià 2b8d1e25d5
Merge pull request #969 from Saibamen/github/label-workflows
ci(labels): checkout before area labeler
2026-10-09 22:58:09 +02:00
Adrià 5694d3fd3e
Merge pull request #2344 from mrzacarias/refactor/np-partner-name-ea-access
refactor(libSceNpPartner001): name the EA access exports
2026-10-09 22:49:12 +02:00
abderahmane-ai bd750b5954 feat(relinker): write a registry for each converted bundled module
--registry only described the imports of the executable, so a title whose
own modules import system functions (PSN.prx, libc.prx and others) could
not be audited completely. With --registry the relinker now also writes
<output-stem>.<module>.registry.json for every converted guest module.

An entry is written for each relocation against an undefined symbol that
no other bundled module exports, the same test the module builder uses to
decide that a dependency is satisfied by a sibling. Entries carry nid,
library and targetOffset; the symbol name no longer has the # suffix by the
time the module is read, so the NID is the bare 11 characters. The
executable's registry is unchanged.

The test converts two modules where one is provided by its sibling, for
Linux and Windows output, covers the DT_RELA and DT_JMPREL tables, checks
that the same module imports the sibling's function once the sibling is
absent, and that nothing is written without --registry. Registered in
CTest as guest_registry.
2026-10-09 22:44:09 +02:00
Saibamen 94ee5e5f91 ci(labels): checkout before area labeler on scheduled runs
Check out the repo when labeling open PRs so actions/labeler reads .github/labeler.yml locally instead of fetching it from the API once per pull request.
2026-10-09 22:44:08 +02:00
Achraf Reyani e8d4c022ea fix(libc): clear the read-only attribute before the single delete
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:23:18 +09:00
popcoder565 570e7affdb Merge remote-tracking branch 'origin/main' into fix/kernel-raise-exception-ntcontinue
Keeps this branch's CONTEXT_FULL | CONTEXT_SEGMENTS read, context-first
order and bounded retry in RaiseOn, and adds #1478's ymm save fields to
both deliveries. The test keeps both phase sets; the vectors phase runs
after the continuing, selfing and looping phases and counts their
deliveries. The TechnicalDebt entry about ymm upper halves is dropped,
since #1478 preserves them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:04:14 -04:00
marcio-ch baa4b07b1b test(libSceRudp): expect sceRudpGetStatus to return instead of throwing
GuestOfflineImports still expected sceRudpGetStatus to throw not-implemented;
the implementation now returns RUDP_ERROR_NOT_INITIALIZED before init and
zeroes the status buffer after it.
2026-10-09 16:57:52 -03:00
MarcZX100 ecf49a5b56 docs(contributing): document CLI for manual Build runs 2026-10-09 19:37:34 +00:00
MarcZX100 db3ccb5481 test(SaveData): drop nonportable directory timestamp check 2026-10-09 19:35:48 +00:00
MarcZX100 4e0e55ff45 fix(SaveData): use C++20 file clock conversion 2026-10-09 19:35:48 +00:00
Ruzi 4f16f7c020 feat(libkernel): implement sceKernelAioPollRequests 2026-10-09 23:02:39 +03:30
Hannah Lyons eb20ba1aaa feat(libc): implement __fpclassifyf 2026-10-09 15:30:00 -04:00
Karan Vora 719f003adf perf(shader): compute v_dot2_f32_f16 in f32 outside the special cases
v_dot2_f32_f16 rounded a.x * b.x + a.y * b.y + c once, computed with f64
TwoSums and round-to-odd. GeForce GPUs run f64 at 1/32 or 1/64 of the
f32 rate, which made it cost about 44 v_fma_f32 on an RTX 4060.

The f16 products are exact in f32, and the correctly rounded sum of
three f32 values only needs f32: two TwoSums, a round-to-odd sum of
their errors and a final add (Boldo and Melquiond, "Emulation of FMA and
Correctly Rounded Sums: Proved Algorithms Using Rounding to Odd",
IEEE TC 57(4), 2008), with round-to-odd emulated by stepping an even
rounded sum one ulp toward its error. With finite inputs, c zero or at
least 2^-100 and a result between 2^-100 and 2^127, every value involved
is zero or a multiple of 2^-123, so no driver flush can reach it. Other
inputs, and zero results, take the f64 lowering in a branch.

New test agc_driver_f32_dot2_rounding checks random, cancelling and tie
cases against an exact fixed-point sum, and the NaN, infinity and zero
rules.
2026-10-09 15:29:37 -04:00
Dean 8b393b6e9a
Merge pull request #759 from Celegans12/feat/agc-guarded-null-pointers
feat(agc): implement deferred faults for reads through null SRT pointers
2026-10-10 08:06:47 +13:00
Dean d93bc7763c
Merge pull request #1004 from Celegans12/perf/agc-staging-pool-reuse
perf(agc): pool device staging buffers by size class
2026-10-10 08:06:32 +13:00
Dean d2612fb586
Merge pull request #1411 from Celegans12/perf/agc-heap-mirror-runs
perf(agc): skip unchanged heap mirror runs and idle mirror sweeps in address-based builds
2026-10-10 08:06:17 +13:00
Dean 05ba7f746a
Merge pull request #1410 from Celegans12/perf/agc-imported-heap-mirrors
perf(agc): release a heap mirror once a host import serves its range
2026-10-10 08:06:03 +13:00
Dean 2af96d1863
Merge pull request #1085 from Celegans12/fix/agc-host-heap-budget
fix(agc): throw instead of aborting when a heap mirror cannot be made
2026-10-10 08:05:48 +13:00
Dean 00dbf93742
Merge pull request #1489 from Celegans12/fix/agc-merged-range-past-import
fix(agc): copy an imported range once a merge extends it past its import
2026-10-10 08:05:33 +13:00
Dean 0c8d5356d7
Merge pull request #1480 from awake-devel/fix/cond-wait-recursive-mutex
fix(libkernel): release every level of a recursive mutex during a cond wait
2026-10-10 08:05:19 +13:00
Dean 87e773689e
Merge pull request #1478 from awake-devel/fix/guest-signal-delivery
fix(libkernel): keep ymm upper halves across a redirected raise
2026-10-10 08:05:04 +13:00
Dean fffb830363
Merge pull request #1477 from awake-devel/fix/current-cpu-in-guest-mask
fix(libkernel): report the current CPU within the thread's guest affinity
2026-10-10 08:04:50 +13:00
Dean ae3d5f95a0
Merge pull request #2414 from oneandonlydean/ci/build-on-current-main
ci(build): build pull requests merged into current main
2026-10-10 07:39:43 +13:00
Dean Galvin 4a53177bc5 ci(build): build pull requests merged into current main
GitHub refreshes merge_commit_sha only when the pull request's branch
changes, so a manual build could test the pull request against a main
from days earlier. Each job now checks out main as it is when the build
starts and merges the pull request head into it.
2026-10-10 07:36:18 +13:00
MathiasDevelopes d5721f34b2 feat(libScePsml): build libScePsml from the libScePsml_debug source
Titles that link the release module libScePsml.prx failed to start
because no host library had that name; PPSA25344 links it. libScePsml
and libScePsml_debug are now built from the same source.
scePsmlMfsrGetDispatchMfsrPacket1000, which PPSA25344 imports, is
added without an implementation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 20:25:55 +02:00
Pouare514 998016e789 fix(libs): drop stubs now owned by main after rebase 2026-10-09 20:13:56 +02:00
Pouare514 c67189fdee fix(libs): export host-colliding runtime names via _nid_postfix 2026-10-09 20:12:46 +02:00
Pouare514 eafeecda82 fix(libs): coexist with main's Http impls, drop Net stub owned by Net PR 2026-10-09 20:12:46 +02:00
Pouare514 b6c70b1135 fix(libs): rename loader stubs to recomputed real names, drop clashing ones 2026-10-09 20:12:31 +02:00
Pouare514 e96ec6da7d feat(libs): Deathloop loading support (Ampr, NetCtlApDialog, Party + stubs) 2026-10-09 20:11:35 +02:00
Karan Vora 8a578128b2 perf(shader): convert v_cvt_pkrtz_f16_f32 from the native nearest-even conversion
With the 16-bit RoundingModeRTE, DenormPreserve and
SignedZeroInfNanPreserve guarantees, convert each value to the nearest
half with OpFConvert, convert the half back to f32 and, when it is
further from zero than the source, step its bits one toward zero. That is
the toward-zero half for every finite value, including subnormal results
and 65504 for values from 65520 up; infinities and the quiet NaN with
the high payload bits are kept. Other devices keep the integer
conversion.

New test agc_driver_f16_pack_toward_zero checks every half, its f32
neighbours and the midpoints to the next half, with both signs.
2026-10-09 14:11:02 -04:00
MathiasDevelopes 7142b6e76f feat(recompiler): convert f32 to f16 natively when the device rounds 16-bit floats to nearest even
The integer emulation of the round-to-nearest-even float-to-half
conversion is exact but costly: a compute shader with about 3600
conversions never finished compiling on NVIDIA. When the device enables
shaderFloat16 and guarantees shaderRoundingModeRTEFloat16,
shaderDenormPreserveFloat16 and shaderSignedZeroInfNanPreserveFloat16,
it advertises Float16, RoundingModeRTE and DenormPreserve, and the
recompiler emits OpFConvert under the 16-bit RoundingModeRTE,
DenormPreserve and SignedZeroInfNanPreserve execution modes instead.
NaNs keep the emulated quiet NaN with the high payload bits. Devices
without these guarantees keep the emulation.

Graphics validation accepts the RoundingModeRTE, DenormPreserve and
SignedZeroInfNanPreserve execution modes for 16-, 32- and 64-bit floats,
so vertex and pixel shaders with a native conversion still draw.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 14:11:02 -04:00
Pouare514 4a6775c389 fix(tools): stubgen imports NID scheme, fixes libkernel TD path 2026-10-09 20:08:56 +02:00
Pouare514 85720b9b57 fix(tools): stubgen uses real names plain, runtime postfix, TD lines 2026-10-09 20:07:07 +02:00
Pouare514 ddca247c0d fix(tools): stubgen emits throwing stubs only, no comments 2026-10-09 20:07:07 +02:00
Pouare514 e8e308fc23 feat(tools): generate Export.cpp skeletons from missing NIDs 2026-10-09 20:07:07 +02:00
Gerard L. b6a9530723 fix(agc): use gfx1013's smaller mip tail limits for 8 and 16 bpp SW_64KB_Z_X
The smallest mip levels of a tiled surface are packed together into one
block, the mip tail. A size limit decides which level is the first to
go into the tail.

For SW_64KB_Z_X, AnyPS5 used the same limit as the other 64 KiB modes.
In addrlib, that is only the case on Navi10. On every other GFX10 chip,
including the PS5's gfx1013, addrlib halves the limit for 8 and 16 bpp
Z_X surfaces: the width at both sizes, and also the height at 8 bpp.
The setting behind this is dsMipmapHtileFix (see HwlConvertChipFamily
and ComputeSurfaceInfoMacroTiled in gfx10addrlib.cpp).

With the larger limit, the tail started too early. For example, a
256x256 R8 surface with 9 levels started its tail at mip 1 instead of
mip 2, and took 131072 bytes instead of 196608. Every level was then
read and written back at the wrong offset.

GetMipTailLayout now halves the limits the same way. Only the level
where the tail starts changes; the tail slot positions stay the same.
This follows addrlib's setting for gfx1013. The console's own layout
has not been measured.

Fixes #1590

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:06:51 +02:00
Karan Vora 3a16e5e54e perf(shader): round v_cvt_pknorm and v_cvt_pk_u8 in f32
v_cvt_pknorm_i16/u16_f32 rounded |x| * 32767 or 65535 to nearest even
with a 64-bit integer product, variable 64-bit shifts and a sticky bit.
In f32, p = |x| * scale is the f32 nearest to the exact product, so
roundEven(p) is the answer unless p is exactly k + 0.5, where the sign of
the exact error fma(|x|, scale, -p) decides. Lanes that select a
constant (NaN, |x| >= 1) multiply 0 instead.

v_cvt_pk_u8_f32 truncated with the saturating conversion and rounded the
fraction by hand; it is now roundEven(x) between the 0 and 255 clamps,
NaN giving 0, read without the f32 denormal flush.

New test agc_driver_f32_pack_rounding: 563,232 inputs around every
rounding tie, checked against the exact product in double.
2026-10-09 14:05:07 -04:00
Nahuel Genchi 230625e080 fix(libc): return ENOMEM from posix_memalign for sizes the default heap rejects 2026-10-09 15:03:07 -03:00
Archit Dewan 4a5cd6e40b fix(ajm): reject ATRAC9 gradients beyond decoder bounds 2026-10-09 13:53:46 -04:00
MarcZX100 49887893a4 test(hmd): register disconnected-device tests 2026-10-09 17:47:28 +00:00
MarcZX100 bcaccb6e20 test(libkernel): set pthread test timeout by platform 2026-10-09 17:46:21 +00:00
MarcZX100 74a7a4ab05 test(libkernel): register pthread start coverage 2026-10-09 17:46:21 +00:00
Karan Vora 42692dee11 perf(shader): fold the denormal flush into f32 compares against constants
When f32 denormals are flushed, v_cmp_*_f32 compares flush(a) with
flush(b). With one operand a constant, the flush of the other operand
can go into the compare: a denormal and its flushed zero compare the same
way with a NaN, an infinity or a normal constant, and comparing flush(x)
with a zero is comparing x with +-2^-126 (flush(x) < 0 is x <= -2^-126,
flush(x) == 0 is |x| < 2^-126, and so on, the unordered forms alike).

emitFloatCompare reads both operands unflushed, finds a constant operand
after its abs/neg modifiers, mirrors the predicate when the constant is
first, and emits one compare. Two registers, f16 compares and modes that
keep f32 denormals are unchanged. New test agc_driver_f32_compare_constant
checks all 12 predicates against flush(a) op flush(b).
2026-10-09 13:38:56 -04:00
MarcZX100 d809ccf797 test(libc): cover getcwd zero-size buffer 2026-10-09 17:38:45 +00:00
Hannah Lyons 7d130d1b4b test(libkernel): check getdents errno on success and closed descriptors 2026-10-09 13:30:45 -04:00
Hannah Lyons d6963f46d6 feat(libkernel): implement getdents and getdirentries 2026-10-09 13:30:45 -04:00
Karan Vora b7df8884ff perf(shader): saturate f32 to integer conversions once
The translation of v_cvt_i32/u32/flr_i32/rpi_i32_f32 and v_cvt_i16/u16_f16
already maps NaN to 0 and clamps the value into range before
ConvertS32F32/ConvertU32F32, and the backend truncated it again and
repeated the NaN and range selects on the result. Those IR ops have no
other producers, so the backend now emits one OpConvertFToS or
OpConvertFToU, and EmitF32ToU32 and EmitTruncF32Value, which had no
other users, are removed.

The translation drops its FPTrunc32, as the conversions round toward
zero, and the selects whose constant the conversion of the clamped value
already gives. v_cvt_i32_f32 and v_cvt_u32_f32 read their source without
the f32 denormal flush: a denormal truncates to 0 either way.
2026-10-09 13:28:39 -04:00
authurtabo-byte ce66d2688e fix(libSceAudioOut): allow state queries during output waits 2026-10-09 10:24:31 -07:00
authurtabo-byte f8b9b04dd1 fix(libSceSaveData): accept 32 MiB save memory 2026-10-09 10:24:30 -07:00
boykopovar f8c2f07246
Merge pull request #2388 from boykopovar/ci/pr-intake-minimum-20
Ci/pr intake minimum 20
2026-10-09 20:16:52 +03:00
boykopovar e6e92e7402 refactor(ci): simplify pr intake closure message 2026-10-09 20:16:05 +03:00
Daniel Radosa 1414b27d29 feat(libkernel): implement seteuid and setegid
The guest process is assumed to run as root. Under FreeBSD's
sys_seteuid and sys_setegid, id 0 is then accepted without a privilege
check and changes no credential, so both return 0. Any other id would
change the effective credential, which is not modelled, and throws.

Part of #1578.
2026-10-09 19:14:02 +02:00
boykopovar 9a03dad6fb ci(prs): require 20 merged prs for pr intake 2026-10-09 20:12:52 +03:00
boykopovar 0fdda7be94
Merge pull request #2374 from boykopovar/ci/reject-newcomers-pr-task
ci(prs): close prs from new contributors while intake is paused
2026-10-09 19:49:29 +03:00
krishnaraya dffd449489 fix(shader): give 10_10_10_2 integer vertex inputs an integer type
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 12:49:25 -04:00
boykopovar af39aac1a2 ci(prs): close prs from new contributors while intake is paused 2026-10-09 19:46:43 +03:00
husari.orozco 1c6e53b9bf ci(conventions): exempt cmake/SystemDeps.cmake from the system-dependency rule 2026-10-09 10:46:35 -06:00
Celegans12 fcc5105aeb fix(shader): count folded draw offsets once in the vertex and instance indices
When the embedded vertex fetch adds the base vertex or start instance
user SGPR to the index VGPR, the driver folds that SGPR into the draw's
first vertex and first instance. v5/v8 were gl_VertexIndex and
gl_InstanceIndex, which already include it, so the translated add
counted it twice, on direct draws and CPU-path indirect records alike.
The entry of a vertex or local program now subtracts the folded SGPR's
user data word from the builtin, which gives the zero-based indices the
hardware has. A record drawn in place on the GPU keeps the CPU's word,
so the fetch analyzer counts the SGPR as shared unless the fetch add is
the only reader of v5/v8 and the SGPR (no earlier access or EXEC write,
no carry, clamp, second add or other write of the SGPR); such records
take the CPU path. The fold moves into Driver::FoldDrawOffsets,
ClassifyIndirectDraw becomes public for the test, and the env switches
that skipped the fold go.
2026-10-09 18:41:51 +02:00
Joey Fisher f00c2f2d16 fix(recompiler): apply the S_BFE_U32 width when the vertex fetch scanner folds constants 2026-10-09 10:37:40 -06:00
krishnaraya 2ea1f6fb71 fix(shader): stop decoding gfx6/7-only VOP2 opcodes on RDNA
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 12:30:40 -04:00
klosixgaming-arch 0b82fc4cf1
Merge branch 'main' into bionic/fix-intel-smulextended-v2 2026-10-09 11:28:35 -05:00
Karan Vora d220f48e92 perf(shader): load from buffers without Coherent when the load has no GLC or DLC
A program with one GLC or DLC buffer load or store decorated the whole
guest buffer array Coherent, so its other loads were coherent too. On
NVIDIA that keeps them out of the L1 cache: one GLC store made the
re-reads of a 4 KiB window about 2.7 times slower.

RDNA keeps those loads incoherent. A load without GLC or DLC can hit the
per-CU L0 and per-SA L1 caches, which are not coherent between
work-groups, and code that needs another work-group's data reads it
with GLC/DLC or invalidates the caches first (LLVM AMDGPU memory model,
GFX10: an acquiring load is followed by buffer_gl1_inv; buffer_gl0_inv).

The program metadata now records whether a program invalidates a cache
(buffer_gl0_inv, buffer_gl1_inv, s_gl1_inv, s_dcache_inv). Without one,
a program with GLC/DLC accesses gets a second array on the same binding,
buffers_coherent, decorated Coherent, and both arrays are Aliased as
buffers_u64 already is. Loads without GLC or DLC read buffers; GLC/DLC
loads, stores and atomics use buffers_coherent. A program that
invalidates a cache keeps the whole array Coherent.
2026-10-09 12:22:04 -04:00
marcio-ch adbd8f5e68 feat(libSceRudp): implement sceRudpGetStatus
Zero the status buffer after initialization like sceRudpGetContextStatus,
and return the not-initialized error before it, instead of throwing.
2026-10-09 13:17:26 -03:00
Aerovity 1a2ca5678d ci(labels): create unforced labels only when they are missing
gh label create exits non-zero for a label that already exists, and the
step runs with bash -e, so the first existing unforced label stopped the
job. Skip labels that already exist, keeping hand-set colors.

Fixes #2320

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 18:12:45 +02:00
Nahuel Genchi 6c81134f79 fix(libkernel): submit APR command buffers that were not constructed
sceKernelAprSubmitCommandBuffer rejected a buffer object with EINVAL
unless sceAmprAprCommandBufferConstructor had tagged it. The tag is
AnyPS5's own: in the retail layout the type word only carries state
bits and the constructors zero the object, so a zero-filled object
bound with SetBuffer is a valid APR buffer.

CRI's file system in Sonic Origins (PPSA05324) lays out its
AprCommandBuffer objects in its own zeroed work memory and never calls
the constructors. Its first read submit failed with 0x80020016, and the
CRI file system stopped there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:10:44 -03:00
Mouhand-Kaddo c80bea9b88 fix(posix): configure resolver tests for Windows unwinding 2026-10-09 20:07:54 +04:00
marcio-ch fc3e2345c0 refactor(libSceNpPartner001): name the EA access exports
sceNpEAAccessInitialize and sceNpEAAccessTerminate resolve the NIDs
7CxI50-xlCk and pMxXhNozUX8, which shadPS4 names in np_partner.cpp. The
stubs still throw; only the names and no-argument signatures change.
2026-10-09 12:57:50 -03:00
Achraf Reyani 58e18f0828 fix(libc): remove read-only files on Windows
FreeBSD's unlink ignores the file's own permission bits, so remove()
succeeds on a file the guest made read-only with chmod(0400). On Windows
the guest chmod sets FILE_ATTRIBUTE_READONLY, and DeleteFileW then fails
with ERROR_ACCESS_DENIED, which remove() reported as EACCES. Clear the
attribute and retry, restoring it if the retry still fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:55:32 +09:00
JAB-dev 255ed1de7c test(libSceNgs2.native): keep the matrix level clamp clear of the other NGS2 changes
Use INFINITY and NAN from <cmath> instead of a new <limits> include, and
list the TechnicalDebt entry beside the other NGS2 voice entries, so the
change merges cleanly with the pan, channel map and reverb changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:55:06 +02:00
ale 8d30c27589 feat(hw-oracle): make the group segment size an option
The template allocated a fixed 4 KiB of LDS, so kernels with immediate
offsets past it could not run. --lds (Python lds) sets the group segment
size in bytes, up to 64 KiB, with 4096 as the default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 12:47:59 -03:00
Josip Parlov 48b7d73dd7 docs: drop the stale unknown-signature entries for the memory pool stats 2026-10-09 17:46:35 +02:00
Achraf Reyani 46786b1e91 fix(libc): read directory entries through the wide dirent API on Windows
The guest passes and expects UTF-8 names, but on Windows opendir and
readdir used MinGW's narrow dirent API, which works in the ANSI code
page: opendir failed for a directory whose name is outside the code page,
and readdir returned names as ANSI bytes, with "?" for characters the code
page lacks. Use _wopendir and _wreaddir there and convert each name to
UTF-8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:45:18 +09:00
JAB-dev 473ca04b2f fix(libSceNgs2.native): throw on reverb rack sizes and sample rates the reverb does not handle
A reverb_size other than the default was accepted and ignored, and below
about 7.5 kHz an allpass length went negative and wrapped to a 16 GB buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:38:18 +02:00
EdouardSence ab09a0a975 fix(agc): accept disabled conservative rasterization with uncertainty-region bits
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:38:13 +02:00
Scott Schuster bbdb35b195 fix(libc): check a whole range before collecting its writes with reset
WindowsMappings::Collect resets each part of the range as it walks it:
it marks shared views seen and resets private pages' write-watch bits.
When it then met a NOACCESS view or memory that is not committed
private memory, it returned false with the earlier parts already reset,
so their writes were lost to the caller's fallback. With reset, the
whole range is now checked first and nothing is reset when it fails.

AI-assisted (Claude Code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:36:55 -05:00
Joey Fisher 36997299e9 test(agc): check that streaming-feedback T# fields share a sampled texture entry 2026-10-09 09:32:23 -06:00
Josip Parlov 9cea268f9e refactor(libc): name the 12 Cyberpunk stubs the NID database resolves 2026-10-09 17:32:08 +02:00
Mouhand-Kaddo a1e2781f80 fix(posix): match FreeBSD numeric IPv4 lookups
Parse legacy decimal, octal and hexadecimal forms before host lookup. Preserve FreeBSD shorthand, whitespace and 64-bit accumulation, clear the SDK resolver error on numeric success, and add regression coverage.
2026-10-09 19:31:56 +04:00
Achraf Reyani d8c5d142b6 fix(libc): allocate getcwd's buffer from the application heap
getcwd(NULL, size) returned memory from the guest heap directly, while
the caller frees it with free(), which goes to the application heap.
With a title's malloc replacement registered, that free reached the
replacement with a pointer it never returned. Allocate from the
application heap like strdup, and report ENOMEM when it returns null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:26:48 +09:00
Josip Parlov c90f85535e refactor(agc): name HV4j+E0MBHE sceAgcCreateInterpolantMapping_0100 2026-10-09 17:25:54 +02:00
Mouhand-Kaddo 4c7e823294 feat(opus): implement 48 kHz libSceOpusDec
Decode raw mono and stereo packets for missing system-library imports. Add behavioral tests and document unverified firmware semantics.
2026-10-09 19:24:56 +04:00
Mouhand-Kaddo d14f036122 feat(posix): implement gethostbyname
Resolve the missing EVO-PLAYER import reported in #1578. Convert native host entries into the guest ABI with owned per-thread storage, and use the SDK network error location for failures.
2026-10-09 19:24:55 +04:00
Mouhand-Kaddo e0b0d087cc test(posix): cover gethostbyname guest results
Check numeric address bytes, guest hostent fields, per-thread result lifetime, and the SDK resolver error location. The check currently fails to link because the reported export is missing.
2026-10-09 19:24:55 +04:00
klosixgaming-arch dd0d8cd425 fix(shader): work around Intel iGPU OpSMulExtended bug 2026-10-09 10:20:14 -05:00
Karan Vora 9996baaf41 perf(shader): pick f32 min, max and med3 results with fewer selects
EmitClassifyF32Bits found a NaN from the exponent and mantissa fields
separately. The magnitude settles it: a NaN is above 0x7f800000 and a
zero is 0.

min and max ended with two NaN selects. An ordered compare is false when
either operand is a NaN, so the ordered pick already returns rhs for a
NaN lhs; only the select that returns lhs for a NaN rhs, also when both
are NaNs, is needed.

med3 is the minimum of the three when any operand is a NaN and the
median otherwise. The median is used only without NaNs, so it is now
built from compares and the zero-sign rule alone, and the minimum reuses
the operands' NaN tests instead of classifying intermediate values.
2026-10-09 11:18:19 -04:00
Joey Fisher 24e33365f0 perf(agc): key sampled textures without the streaming-feedback fields
MIN_LOD_WARN, MIP_STATS_COUNTER_EN and MIP_STATS_COUNTER_ID are ignored by the texture decoder, but the cache
key held the raw T# words. A title that rotates the counter fields per use got a cache entry per variant of the
same texture, and the extra entries evicted live ones under the budget.
2026-10-09 09:14:22 -06:00
popcoder565 3b0454dadf test(agc-driver): retire the unit shadow block's import before releasing it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:59:12 -04:00
Josip Parlov 61684ce98f test(net): reset the closed peer with unread data so the send fails at once 2026-10-09 16:53:26 +02:00
Alex 270f375c82 fix(agc): skip prim state preparation for a patch/hull mismatch
sceAgcCreatePrimState only packs registers, but it now also resolves the
graphics ABI ahead of time, and that resolve throws when the primitive
type is a patch list without HS_EN or a hull stage with another type.
No draw can use such a state, so leave it to draw time and return the
registers. Bit 2 of VGT_SHADER_STAGES_EN is HS_EN, not an NGG bit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 16:49:28 +02:00
Pedro a1efdab629 fix(videoout): cancel flips on a port the title closed instead of failing the driver
A flip still queued or in presentation when the title closes its port is discarded, as on hardware, rather than stored as a driver failure. A closed port no longer terminates the presentation thread nor surfaces from Shutdown. The lifetime test now expects cancellation and the reopen mode is registered in ctest.
2026-10-09 09:42:53 -05:00
Pedro 59c98bde58 test(videoout): limit the flip tests to the 30 second contribution timeout 2026-10-09 09:40:45 -05:00
Karan Vora 3a2494e533 perf(shader): choose the fma NaN result only when the result is NaN
#2083 chooses the NaN result of the f32 fma family on the bits: the first
NaN source, quieted in IEEE mode, with the addend skipped when the
product is infinity times zero, and 0xffc00000 otherwise. The selection
and the infinity-times-zero test ran for every fma, but a NaN source
always gives a NaN result, so for any other result they return it
unchanged.

FPNanResultFma32 carries the result and the three sources, with the IEEE
mode as a flag. The SPIR-V emitter makes the selection, including the
infinity-times-zero test, in a branch taken only for a NaN result, and
the SRT evaluator computes it exactly. Add, sub and mul keep the inline
selects: with two sources a branch costs more than it saves.
2026-10-09 10:27:36 -04:00
eljackjoestar-cmd 4dc29440d5 fix(rtc): validate ticks before timezone conversion 2026-10-09 18:20:55 +04:00
eljackjoestar-cmd d31100a0f2 fix(agc): release shader modules after pipeline creation 2026-10-09 18:19:43 +04:00
Andreas 69063dc1ef fix(libkernel): initialize guest rwlocks before they are shared
winpthreads initializes a PTHREAD_RWLOCK_INITIALIZER lock on its first
use and fails a concurrent first lock with EINVAL. std::shared_timed_mutex
ignores that result in release builds, so two guest threads could both
hold a fresh guest rwlock.

Lock and unlock the mutex once when the guest rwlock is created, before
another thread can reach it, and record the remaining host exposure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:13:41 +02:00
xXPBSXx 0ccfbe46a5 docs(build): note antivirus quarantine of relinker test executables on Windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 15:56:29 +02:00
Tomás Ortellado a213a26b47 fix(relinker): validate ELF identification before parsing 2026-10-09 10:44:31 -03:00
Achraf Reyani 275163277b fix(libkernel): return EPERM when unlinking a directory
FreeBSD's unlink(2) reports EPERM for a directory, but the host call
returns EACCES on Windows and EISDIR on Linux, so the guest saw a
different error on each host. Check for a directory, not following a
symbolic link, before unlinking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:39:50 +09:00
Tomás Ortellado a406ad4df7 fix(relinker): keep input checks compatible with module discovery 2026-10-09 10:38:17 -03:00
JohnM c1b4eb2001 fix(tools): exit 2 when import_audit cannot read an input or write --json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:35:49 +08:00
Tomás Ortellado ec5a2019b2 fix(relinker): reject truncated EH frame headers 2026-10-09 10:24:04 -03:00
Jan Šlégl 1078608783 feat(libkernel): implement munlock beside mlock
sceKernelMunlock and the POSIX munlock unlock the page-rounded range with
FreeBSD's results: 0 for a mapped range whether or not it is locked, EINVAL
for a range that wraps around zero, ENOMEM for an unmapped range. On Linux
the host munlock gives them. On Windows a reserved placeholder counts as
mapped only while the guest reservation or protection registry covers it,
and a region VirtualUnlock refuses as not fully locked is unlocked page by
page, as VirtualUnlock is all-or-nothing. sceKernelMlock shares the range
rounding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GLfKH7Sqe51wX254k1XsV
2026-10-09 15:14:57 +02:00
PrintOrb cf744a3740 fix(tools): preserve UTF-8 in progress comparisons 2026-10-09 08:10:27 -05:00
Tomás Ortellado 682d6f62a3 fix(relinker): reject overflowing signed unwind LEB128 values 2026-10-09 10:05:26 -03:00
meiz 15a877892b
Merge branch 'boykopovar:main' into claude/agc-fail-flips-before-report 2026-10-09 16:03:13 +03:00
Celegans12 8426cab241 perf(agc): keep sampled textures that are bound or used this frame
The sampled texture cache let go of its least recently used entry even
when a build, a recorded batch or a cached resource set still held that
texture, which frees no memory and makes the next lookup create a
second copy. A frame that samples more textures than the cache holds
also missed on all of them every frame.

Eviction passes over an entry whose texture is held elsewhere, or a
view of a cached storage image, up to a quarter over the budget, and
rescans for released textures about once a second. While the least
recently used entry was used in this frame or the previous one, a
texture's first use in the frame is returned uncached and only a second
use evicts, so the next frame finds the cached textures again, even
after an early miss; a new set replaces the old one on its second
frame. APS5_PROFILE_DRAW prints the cache's counts every 10 s.
2026-10-09 14:58:27 +02:00
Celegans12 28345b0eac perf(agc): pool device staging buffers by size class
The device-local tier of BufferPool only reused a buffer of the exact
size and usage it was asked for. Partial storage-image detiles and
retiles ask for a new size and the other transfer direction almost
every time, so the tier sat at its budget and missed and evicted
dozens of buffers per frame, and the vkFreeMemory calls on the release
thread held up submits and allocations on the recording threads.

Device-tier requests of 1 MiB and more now round up to an eighth of
their octave, the tier's buffers are created for storage and both
transfer directions, and a request takes the smallest retained buffer
from its own class up to twice its size. Host tiers, the budget and
eviction are unchanged. agc_buffer_pool covers the classes, the fit
and its bound, reuse only after release, the budget and the unchanged
lists.
2026-10-09 14:58:21 +02:00
Celegans12 4709920641 fix(agc): throw instead of aborting when a heap mirror cannot be made
An address-based build whose heap mirror the device refused, or one past
APS5_HEAP_MIRROR_MIB, stopped the process inside acquireMirror. PPSA26344
hit it at 478 s with 6.8 GiB of heap mirrors beside the host imports.

- a mirror that would go past the budget first sweeps the mirrors whose
  registered range is gone, before its allocation; if it still does not
  fit, the build throws "past the budget"
- the mirror is allocated once: a refusal throws with the range, the
  Vulkan result and the mirror totals, so the draw or dispatch fails like
  any other allocation; nothing is registered for the refused range
- the BDA resource tests run with a 4 MiB mirror budget and a mock memory
  limit: a mirror past the budget is made in the swept mirror's memory,
  and a refused one fails after a single allocation attempt
2026-10-09 14:58:20 +02:00
Celegans12 5623c0e937 perf(shader): share the BDA dword span read between read sites
Every BDA dword read site still emitted in the entry function the add
of its first dword address with the overflow fault, a probe_bda_pointer
call, the wide loads, and one read_bda_dword_bytes call per extracted
dword. NVIDIA's pipeline compile time grows with every call left in the
entry function, so large compute programs with a few hundred such reads
spend 47-77 s in vkCreateComputePipelines.

A read site is now one call to a DontInline read_bda_span function, in
a stop and a coherent variant, taking the address, the immediate offset,
the mask of extracted dwords and the pc, which does the same steps in
the same order. Fault reasons, addresses, pcs, Volatile, the stop
behaviour and the APS5_BDA_BYTE_READS path are unchanged.
2026-10-09 14:58:19 +02:00
Celegans12 3f00dc7841 perf(agc): release a heap mirror once a host import serves its range
An address-based build maps every readable registered range: through a
host import when one can be made, else through a heap mirror, a
host-visible copy of the range. A range mirrored while the import budget
was full kept its mirror after a later pass imported it, until the guest
freed the range. The pass then read the range through the import, and the
mirror only held host-visible memory and a second copy of the bytes.

The pass now releases the heap mirror of every range it serves through
an import. Recorded work that bound the mirror keeps it until it
completes. If the import goes away while the range stays registered, the
next pass makes a new mirror from the guest bytes. The [buffers] image
mirrors profile line counts the released mirrors.
2026-10-09 14:58:17 +02:00
Celegans12 e804ce85f7 perf(agc): skip unchanged heap mirror runs and idle mirror sweeps in address-based builds
A build served by the cached address space walked every region of the
space for its mirrors, sorted the heap mirrors, compared each heap
mirror's blocks with the write tracker under its own lock and swept the
whole mirror registry. In an offline replay with 37,000 heap mirrors
that took about 10 ms per build, every build.

The space now keeps its writable mirrors, its sorted heap mirrors and
their adjacent runs from when it is published. Each run is still
flushed and collected; a run with no block stamped since the generation
its last complete check collected skips the per-mirror compare, and that
generation is stored only once the build's blocks were copied. The
registry sweep is skipped while every live mirror's range is held by the
cached address space's lease and no mirror was added, replaced or
dropped since.
2026-10-09 14:58:16 +02:00
Tomás Ortellado dc9c75b576 fix(relinker): protect executable inputs from output overwrites 2026-10-09 09:50:16 -03:00
Raihan Abdul Majid 1680962763 test(libs): report patched libraries that fail to load instead of a loader dialog
LoadLibraryEx with an unresolved import shows the loader's "Entry Point
Not Found" message box unless SEM_FAILCRITICALERRORS is set, so
patched_libraries waited on the dialog until ctest's timeout instead of
printing the failing libraries. Set it at start, as GuestHeapRounding does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:49:57 +07:00
Jan Šlégl 892aa8b5ee feat(libkernel): implement mlock
The POSIX form of sceKernelMlock: 0 on success, -1 with errno (EINVAL,
ENOMEM, EPERM, EAGAIN) where the sce form returns the kernel error, as
munmap and mprotect do beside it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 14:47:29 +02:00
Andreas ba5256333d fix(relinker): root code addresses taken by RIP-relative LEA
Functions referenced only through a REX.W RIP-relative LEA (constructors,
callbacks, thread entries called indirectly) were not reached by code
analysis, so their guest TLS accesses stayed unpatched on Windows.

Add LEA targets inside executable code as roots, both in the instruction
walk and when following the control-flow graph of unreached code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:45:29 +02:00
Jan Šlégl db7666b22c fix(tools): count only definitions as exports in the overlap report
pr_overlap.py took every added line with APS5_VABI before a name and a
parenthesis as an export, so a declaration such as
extern "C" int* APS5_VABI __error_nid_postfix(); made each pull request
that adds it "implement the same function" as all the others. A line
that ends in a semicolon is a declaration and is skipped; every
definition's first line in the tree ends in a brace, a parenthesis or
a comma.

Registers pr_overlap_exports.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 14:43:32 +02:00
Andreas 24474e3d28 fix(libkernel): unmap direct memory views when the memory is released
Releasing direct memory left the virtual ranges that mapped it registered,
so sceKernelVirtualQuery reported them as flexible memory at offset 0 and
titles walking a range with FIND_NEXT released physical page 0.

Collect every view of the released pages before freeing them and unmap
them through UnmapRegistered, as shadPS4's MemoryManager::Free does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:42:17 +02:00
mugurc f3c514744b feat(nid): patch NIDs in Mach-O libraries
nid_patcher turns the _nid_postfix names of a library into NIDs for ELF
and PE. A library built on macOS is a Mach-O dylib, whose exports are in
a dyld export trie and whose imports are in the chained fixups, so it
gets its own patcher.

- The export trie is read, every exported C name (without Mach-O's
  leading underscore) is resolved to its NID, and the trie is rebuilt the
  way ld64 lays it out: the offsets are uleb128, so the layout is repeated
  until it is stable. A trie that no longer fits is appended to
  __LINKEDIT, which has to end the file, and a signed image is refused.
- Weak definitions that are not marked _nid_postfix or _nid_no_patch keep
  their names: dyld coalesces those across images by name.
- In the chained imports, names bound to a .prx dylib that are guest
  facing (a _nid_postfix name or an sce prefix) are patched in place; a
  name that would grow, or that shares storage with another import, is an
  error. Images that use bind opcodes instead of chained fixups are
  refused.
- ExportExclusions reads the exports of a reference Mach-O, so the
  exclusion list works for libraries built on macOS as well.
2026-10-09 15:40:29 +03:00
LuisBiceps 50ee20c7fc Merge remote-tracking branch 'upstream/main' into feat/system-service-web-browser-unavailable 2026-10-09 20:40:00 +08:00
EdouardSence 52b77c2022 fix(agc): defer shaders that cannot be prepared at registration to their first use
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:26:30 +02:00
Ramzi 115a8b050a test(relinker): launch the GUI startup fixtures without Windows Error Reporting
The GUI missing-symbol and missing-module fixtures were started with
ShellExecuteExW. A process the shell starts gets the default error mode,
so the status the entry stub raises reaches Windows Error Reporting as an
APPCRASH. Collecting each report took about 2 s, sometimes over 10 s,
and under a parallel ctest run it could pass the 30 s wait, failing
windows_import_modules with "ShellExecuteExW child did not exit" while
WerFault still held the fixture's files.

The fixtures now start through CreateProcessW with STARTF_USESTDHANDLES
and no standard handles, so the stub's diagnostic still has nowhere to
write, and with the test's error mode, which keeps the report away.
2026-10-09 13:24:01 +01:00
Eshaan Jaiswal 98b449f655 fix(relinker): allow empty relocation tables 2026-10-09 17:52:07 +05:30
Arvind Frøiland f4084d5653 feat(libSceNpManager): answer sceNpCheckNpAvailability with no user signed in
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 21:13:56 +09:00
don 1c71428f82 fix(agc): restore the standalone visual demo 2026-10-09 14:12:24 +02:00
Arvind Frøiland eb1d558fe9 feat(share): answer sceShareSetContentParamForApplicationTitle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 21:02:01 +09:00
Eshaan Jaiswal efe54ad6cb fix(relinker): validate relative relocation table bounds 2026-10-09 17:31:29 +05:30
Pedro 2663699dc5 test(videoout): skip flip tests without a Vulkan window and create param.json
The offscreen SDL driver cannot create a Vulkan window on Windows since
the VideoOut window uses SDL_WINDOW_VULKAN, so the tests that open a port
now exit 77 (skipped) like the other display tests, unless
ANYPS5_REQUIRE_DISPLAY is set. The tests also write app0/sce_sys/param.json,
which AppMetadata now requires.
2026-10-09 06:56:43 -05:00
eliasbruno124-dev 98c47df9e5 fix(relinker): discover required guest module identities 2026-10-09 13:53:48 +02:00
Pedro 3e01e740e4 test(videoout): drop video_out_flip_tests from KNOWN_UNRUN now that ctest runs it 2026-10-09 06:53:27 -05:00
Pedro 64b97c8981 test(videoout): prepend libc dir to PATH for video_out_flip tests on Windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 06:53:27 -05:00
Pedro 43a460cc66 fix(videoout): report GPU driver shutdown failure from the present thread at Shutdown
presentLoop called AgcDriverShutdown outside its try block, so a stored
worker failure rethrown there terminated the process. Store it in
flipQueue->failure so VideoOutDriver::Shutdown rethrows it after the join.

Register the lifetime, decode and controls modes of video_out_flip_tests
in ctest.
2026-10-09 06:53:27 -05:00
darhebkf 357d4d3e8b
fix(tools): check overlap against every open pull request 2026-10-09 13:49:20 +02:00
kali113 d5241d282f fix(relinker): give Linux guest modules a default non-executable stack 2026-10-09 13:45:37 +02:00
Petre Buia 7dc3a067d1 test(agc): flush shader cache writes before removing test files 2026-10-09 13:45:09 +02:00
kali113 68072d6050 test(agc): bound storage cache budget regression workload 2026-10-09 13:44:25 +02:00
Zheorgyan eec5c18279 fix(libc): define APS5_LOG_OUT_DEBUG when APS5_DEBUG_LOG is set 2026-10-09 13:42:51 +02:00
darhebkf a00559a222
fix(tools): preserve function bodies after line comments 2026-10-09 13:42:24 +02:00
Rohan03x a8bc85c5f4 build: skip the FreeType version resource so Windows builds work in paths with spaces
MinGW windres passes -I paths to cc1 with backslash-escaped spaces and
parentheses, so compiling 3rdparty/freetype/src/base/ftver.rc fails when
the checkout or build path contains them. FreeType is linked as a static
library and the resource object is never pulled into an output, so it is
removed from the target's sources on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:36:46 +11:00
Rohan03x 39055977e6 docs(usage): list the MinGW runtime DLLs a self-built libs directory needs
The built Windows libraries import libgcc_s_seh-1.dll, libstdc++-6.dll and
libwinpthread-1.dll, and the entry stub loads them without searching PATH.
The release archives ship the DLLs in libs/, but the runtime layout only
told self-builders to copy the .prx files, which ends in error 126.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:36:45 +11:00
XairRrR 8b7ff670a7 fix(recompiler): bind the rect-list fault buffer in the tessellation control group
The rect-list control and evaluation shaders put their fault buffer one
past the highest vertex or fragment binding. Bindings are grouped per
stage (RuntimeAbi::BindingNumber), so that number could fall inside
another stage's group and collide with one of its bindings, and the
draw failed with a duplicate binding. The fault buffer now uses the
TessellationControl FaultBuffer binding.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at its first rect-list draw with "duplicate shader binding".
2026-10-09 13:28:48 +02:00
XairRrR 09582357f2 fix(recompiler): accept SDWA destination selects on v_not_b32
v_not_b32_sdwa takes the same dst_sel and dst_unused operands as the
other 32-bit VOP1 SDWA forms (RDNA2 ISA 6.3.1 "SDWA"; LLVM
VOP1Instructions.td gives V_NOT_B32 a VOP1_SDWA encoding with dst_sel
and dst_unused). The rule now allows byte and word destinations with
every unused mode, which the existing SDWA writeback implements; the
execution test checks WORD_0 with UNUSED_PRESERVE.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at a v_not_b32_sdwa with dst_sel:WORD_0 dst_unused:UNUSED_PRESERVE.
2026-10-09 13:28:48 +02:00
XairRrR 46a0c1a2c3 feat(agc-driver): sample 8_SNORM images
GFX10 image format 2 (8_SNORM, Mesa gfx10_format_table) resolves to
VK_FORMAT_R8_SNORM and is marked sampleable in the recompiler's format
table.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at a compute shader sampling an 8_SNORM image.
2026-10-09 13:28:48 +02:00
XairRrR 628c656199 fix(agc-driver): ignore marker pops without a pushed marker
Debug markers are NOP payloads the command processor skips, so a pop
with no marker pushed (a title that pops a marker it pushed in an
earlier command buffer) has no effect on the GPU; it no longer throws.

Uncharted: Legacy of Thieves Collection (PPSA05684) pops one marker more than it pushes and stopped with "marker stack underflow".
2026-10-09 13:28:48 +02:00
XairRrR 0fc522d9be fix(agc-driver): rasterize nothing through a zero-scale viewport
A viewport whose X or Y scale is zero maps every vertex onto one line,
so triangle, strip, fan and rect-list draws through it cover no pixel.
Such draws, which titles use to skip work without rebuilding a command
buffer, get a valid 1x1 Vulkan viewport and an empty scissor instead of
throwing. Points, lines and other negative or non-finite scales still
throw.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at such a draw with "unsupported viewport transform: scale=(0, -0, 1)".
2026-10-09 13:28:48 +02:00
XairRrR 60c26120a6 feat(libs): implement libSceVdecsw on top of libSceVideodec2
libSceVdecsw is the software H.264 decoder interface PPSA05684 uses for
its movies. Decoder creation, compute queues, memory queries, decode
input and output, AVC picture info, reset and finalize are implemented
with the layouts of shadPS4's vdecsw.h, checked against the title's
movie decoder, and decode through libSceVideodec2. The H.264 stream the
Videodec2 test uses moves to a shared fixture, and a guest test decodes
it through Vdecsw.

Uncharted: Legacy of Thieves Collection (PPSA05684) plays its movies through libSceVdecsw and stopped at sceVdecswQueryComputeMemoryInfo.
2026-10-09 13:28:48 +02:00
ctj01 1352b9b34d fix(relinker): write Linux PT_LOAD headers in ascending address order
The header-block PT_LOAD has the highest address but was the first
loadable entry in the table. Linux before 5.18 sizes the ET_DYN mapping
from the first and last PT_LOAD entries in table order, so the output
failed to exec with SIGSEGV. Write PT_PHDR and PT_INTERP first, sort the
kept PT_LOAD entries by address, and place the extra and header blocks
after them.
2026-10-09 06:27:23 -05:00
Achraf Reyani 2a52af8509 build(windows): guard NOMINMAX in the kernel sync test
libstdc++ already defines NOMINMAX on MinGW, so the unguarded define
warned on every Windows build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:19:05 +09:00
krishalivaibhav 4361d8c53a test(shader): validate image compilation on SPIR-V 1.3 targets 2026-10-09 16:46:37 +05:30
tezzgod74 5463ea4784 fix(tests): target SPIR-V 1.4 where the prepared graphics test adds mesh shading
The geometry pass adds the mesh capability and extension to the device
target but kept its SPIR-V version. On a device without mesh shaders
that is 1.3, and the mesh module was rejected as exceeding the target.
VulkanDevice targets 1.4 whenever mesh shading is enabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 06:09:32 -05:00
tezzgod74 1774cc9d62 fix(shader): splat the FMASK read condition into a bool vector for SPIR-V 1.3
The FMASK identity read selected a uvec4 with a scalar bool condition,
which needs SPIR-V 1.4. Devices without mesh shaders target 1.3, so
every image test that reaches the path failed validation with
ANYPS5_ENABLE_SPIRV_TOOLS (#2138), as in #574.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 06:09:32 -05:00
Dextroid17 ad1c3924da ci: accept the device limitations the CI jobs actually report 2026-10-09 07:00:35 -04:00
Dextroid17 1924e18f6f ci: fail when a test skips that the job's device is not expected to skip
The Linux job reports "100% tests passed out of 371" with 20 agc_driver execution tests skipped
(llvmpipe reports subgroup size 8, so the tests that need a wider wave exit 77), and the Windows
job reports "100% tests passed, 0 tests failed out of 368" with 143 skipped - the runner has no
Vulkan driver and ANYPS5_REQUIRE_VULKAN is not set there, so 143 of the 147 GPU execution tests
silently do not run. ctest counts a skip as a pass, so neither job notices when the set grows.

Add tools/check_skips.py. It reads the file ctest writes with --output-junit and fails when a test
skips for a reason that is not expected:

- linux: a skip is expected only when the test's own output reports that the device's subgroups
  are too narrow for it, so adding a wave32 test does not need the rule edited;
- windows: any agc_driver test, since the runner has no driver for them, while a skip of anything
  else fails.

Both jobs now pass --output-junit and run the check after ctest. The JUnit file needs no
redirection, so the console output stays visible and no pipe can hide a failing ctest.

Verified here with the CI command and the CI device (lavapipe, subgroup 8): the real run reports
20 skipped, all expected; a 21st wave32 test skipping for the same reason passes; a skip whose
reason is something else exits 1; a file with 143 agc_driver skips passes with --job windows and
one non-agc skip in it exits 1.
2026-10-09 07:00:35 -04:00
Dextroid17 84d851bf81 fix(relinker): bound the symbol table entry read 2026-10-09 06:54:33 -04:00
Aryan Sharma 7fc6fac1af test(libc): move the malloc_stats_fast checks to their own test 2026-10-09 16:22:39 +05:30
Dean d70b899894
Merge pull request #2112 from LeandroLP23/fix/agc-profile-output-shutdown
fix(agc): stop the profile output at shutdown only if it was created
2026-10-09 23:46:21 +13:00
Claude 4a2769f26d
test(net): skip only the IPv6 socket checks on a host without IPv6
On a host without IPv6, socket(AF_INET6) fails with EAFNOSUPPORT, so
guest_sce_net aborted at its first IPv6 socket and never ran the TCP,
UDP, epoll, sendmsg/recvmsg, resolver and NetCtl checks after it.

When sceNetSocket reports guest EAFNOSUPPORT (47) for the IPv6 socket,
skip those socket checks, run the rest of the test, and exit with 77,
which ctest reports as skipped. Hosts with IPv6 run every check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-09 10:30:28 +00:00
Claude 9bd8089cbb
test(agc): compare llvmpipe shader clocks modulo 2^32
llvmpipe builds the high dword of the shader clock with a left shift by
32 (emit_clock in Mesa's lp_bld_nir_soa.c), so it is always 0 and
s_memtime and s_memrealtime wrap every 2^32 ns. A pass of
agc_driver_shader_clock whose two reads straddle a wrap failed with
"memtime: lane N went back from 4294921902 to 3823"; dispatching right
before the boundary fails every lane of that pass.

On llvmpipe compare the low dwords modulo 2^32, which stays correct if
Mesa fixes the shift. Other devices keep the 64-bit comparison.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-09 10:30:28 +00:00
Claude c7b95bc6c5
fix(agc): fail a failed submission's flips before reporting the failure
When a queue worker failed, it published the failure and woke the idle
waiters before failing the flips of the submission it was executing.
A thread returning from AgcDriverWaitIdle with that failure could still
see one of those flips neither completed nor failed, which made
agc_driver_flip fail with "failed flip was completed successfully" in
2 of 240 runs under four-way parallel load on lavapipe.

Fail the executing submission's flips first, as ReportFailure already
does for the pending submissions it drops before it notifies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-09 10:30:28 +00:00
Aryan Sharma bdeef942f7 test(libc): check malloc_stats_fast forwarding and its error paths 2026-10-09 15:58:34 +05:30
Dean 51f69aa218
Merge pull request #1586 from awake-devel/fix/relinker-keep-eh-frame-hdr
fix(relinker): keep PT_GNU_EH_FRAME in the relinked executable
2026-10-09 23:25:35 +13:00
Daniele Giovane fbce671015 test(libc): verify register contexts on Linux and macOS 2026-10-09 12:22:14 +02:00
Daniele Giovane 9313a9ea1a feat(libc): support register context transfer on macOS x86-64 2026-10-09 12:22:14 +02:00
Sanjaysrinivas b2c825b91b fix(shader): support wave32 mesh programs
Use the guest wave width when constructing NGG mesh entry registers. Add resource-analysis boundaries and indexed/non-indexed rendering regressions.
2026-10-09 12:14:57 +02:00
Angel b6f42c75d8 fix(avplayer): read the PS5 SceAvPlayerInitDataEx layout
PS5 titles pass a 0x230-byte SceAvPlayerInitDataEx: auto start is the
byte after debug_level at 0x74, nine 0x30-byte thread parameter blocks
fill 0x78-0x228 and the output video frame buffer count is at 0x228.
sceAvPlayerInitEx read both fields at their PS4 offsets: auto start at
0xa8 is the video decoder thread priority and the buffer count at 0xa4
lies in the audio decoder block. PPSA25063 (Poppy Playtime: Chapter 4)
sets every thread priority to 700, so its intro video started on its
own and stopped at once; it writes auto start 0 and starts playback
itself.

With this_size 0x230 or more both fields are read at the PS5 offsets;
smaller structures are read as before. The layout follows KytyPS5,
prosper, SharpProspero and sharpemu and is recorded in TechnicalDebt.

guest_avplayer builds a 0x230-byte structure with auto start 0 and
nonzero thread parameters, then with auto start 1, and checks when
playback starts and how many video buffers are allocated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:14:01 +02:00
Celegans12 52eb4272de fix(agc): copy an imported range once a merge extends it past its import
An address-based build maps each imported registered range through its
host import. UploadPrepare merges a descriptor range or snapshot
overlapping such a range into the range's region, and the region kept
the import even when the merge took it past the import's end, as a V#
crossing into the next registered range does. Descriptor then bound the
import's buffer beyond its size, and the BDA table mapped the whole
region, the next range included, through the import's device address.

A merge that extends a region past its end now drops the import. The
region then takes the import lookup and, with no import covering it,
the copy path, as a range crossing an image mirror's end already does.
Like every copied range, it is read-only to pointer stores.
2026-10-09 12:11:06 +02:00
Dean 745b775e2d
Merge pull request #2151 from oneandonlydean/fix/hw-oracle-amdgpu-skip
fix(hw-oracle): skip the wave64 assembly test when clang has no AMDGPU target
2026-10-09 23:10:00 +13:00
Dean Galvin e0a8297a7b fix(hw-oracle): skip the wave64 assembly test when clang has no AMDGPU target 2026-10-09 23:05:41 +13:00
Dean 47d254479d
Merge pull request #2147 from oneandonlydean/ci/build-merge-ref
ci(build): build pull requests merged into current main
2026-10-09 23:05:17 +13:00
Zheorgyan ed8bf0bd14 test(ajm): use a synthetic AT9 block that stays inside the gradient table 2026-10-09 12:03:22 +02:00
MathiasDevelopes 10f57dea29 feat(libSceVideoOut): deliver pre-vblank start events
sceVideoOutAddPreVblankStartEvent threw "physical pre-vblank timing is
not implemented", so titles that pace on it stopped at startup. It now
registers the event like the vblank event does, and each emulated vblank
tick triggers the pre-vblank start events just before the vblank events,
with the pre-vblank count as data. The console's lead time is unknown.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 12:00:55 +02:00
Dean Galvin 5994806a8b ci(build): build pull requests merged into current main 2026-10-09 23:00:01 +13:00
boykopovar 43972e69a1
Merge pull request #2096 from boykopovar/fix/windows-host-import-texture-reuploads
fix(win): windows host import texture reuploads
2026-10-09 12:56:45 +03:00
Dean ede2a9cb1f
Merge pull request #1711 from SleglJan/feat/libkernel-socketpair
feat(libkernel): implement socketpair
2026-10-09 22:55:53 +13:00
Zheorgyan d1a3d42121 fix(agc): remove display upload logs 2026-10-09 11:50:14 +02:00
Dean 3bd74c155d
Merge pull request #1989 from yeahboi233/fix/pr-overlap-utf8
fix(tools): decode overlap command output as UTF-8
2026-10-09 22:43:19 +13:00
Dean b7218b3cec
Merge pull request #1962 from CouchRiv/fix-hw-oracle-wave64
fix(hw-oracle): assemble wave64 bodies in wave64 mode
2026-10-09 22:43:05 +13:00
Dean 34b881e326
Merge pull request #1542 from ska2704/fix/oracle-cache-publication
fix(oracle): publish cached executable only after successful build
2026-10-09 22:42:51 +13:00
Dean 2c3a386e29
Merge pull request #2075 from jdmagic/feat/audioout2-mastering-term
feat(libSceAudioOut): accept sceAudioOut2MasteringTerm
2026-10-09 22:42:37 +13:00
Dean a7ff88524d
Merge pull request #2074 from jdmagic/feat/ppsa01289-missing-exports
feat(libs): provide the exports PPSA01289 imports that no library has
2026-10-09 22:42:23 +13:00
Dean 1d7c70a752
Merge pull request #1992 from LuisBiceps/feat/system-service-kill-app
feat(libSceSystemService): let the running title close itself with sceSystemServiceKillApp
2026-10-09 22:42:08 +13:00
Dean 6a2b99b82d
Merge pull request #1811 from gerardlesan/test/agc-mesh-ctest
test(agc): run agc_driver_mesh_tests under ctest
2026-10-09 22:41:54 +13:00
Dean fdaa12c044
Merge pull request #2073 from jdmagic/fix/ampr-clearbuffer-returns-buffer
fix(libSceAmpr): sceAmprCommandBufferClearBuffer returns the detached buffer
2026-10-09 22:41:40 +13:00
Dean 2bf781eabb
Merge pull request #1856 from sarohy03/test/cli-args-coverage
test(relinker): cover CLI argument parsing
2026-10-09 22:41:25 +13:00
Dean 7bb7cc9bcb
Merge pull request #1445 from Deftera186/fix/shader-fma-mix-fused
test(shader): check v_fma_mix_f32 in FmaRounding
2026-10-09 22:41:10 +13:00
Dean da8345b00d
Merge pull request #1269 from st44rplatinum/feat/systemservice-mediaplay
feat(libSceSystemService): implement Disable/ReenableMediaPlay
2026-10-09 22:40:54 +13:00
Dean ca2b341852
Merge pull request #1059 from Celegans12/perf/agc-storage-image-cache-size
perf(agc): size the storage and sampled texture caches to the device
2026-10-09 22:40:39 +13:00
LeandroLP23 c2231a821a fix(ajm): throw for a null buffer list with a nonzero count
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:37:04 +02:00
LeandroLP23 2bdb979e69 fix: clear the GCC warnings in ProfileOutput, fopen, Ajm batch jobs and the SHA-256 test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:37:04 +02:00
boykopovar 1c1c585722
Merge pull request #2125 from boykopovar/fix/ci-checks-after-merge
fix(ci): restore all builds and tests on main pushes
2026-10-09 12:36:40 +03:00
MathiasDevelopes e70e81dc45 fix(libSceAgcDriver): SPI_PS_INPUT_CNTL registers start at their clear-state value
A title that never writes SPI_PS_INPUT_CNTL_0 relies on its clear-state
value 0, but the register was absent from the initial context, so every
draw of a pixel shader with interpolants was rejected with "missing
register at DWORD 0x191". All 32 SPI_PS_INPUT_CNTL registers now start at
0, as in the GFX10 clear state, both initially and after CLEAR_STATE.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 11:30:38 +02:00
Jordan Hans 6de064f6d3 fix(shader): round the f16 fused multiply-adds once
v_fma_f16, v_fmac_f16, v_fmamk_f16, v_fmaak_f16, v_pk_fma_f16 and
v_pk_fmac_f16 rounded an f32 fused multiply-add to f16, rounding twice.
The product of two f16 values is exact in f32, so the sum is now rounded
to odd in f32 with an exact error term and then rounded to nearest even
in f16, which rounds the exact result once.
2026-10-09 09:28:33 +00:00
Negesin 4491fa9670 test(agc): skip unsupported int64 atomic subcase 2026-10-09 11:23:21 +02:00
LeandroLP23 98427685e0 fix(agc): stop the profile output at shutdown only if it was created
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:22:30 +02:00
boykopovar 10d52b69f3 fix(ci): restore all builds and tests on main pushes 2026-10-09 12:20:50 +03:00
raghav314 f57d1647b5 perf(recompiler): compute post-dominators visiting successors first
computePostDominators iterates its sets to a fixed point, visiting the
blocks in id order. Post-dominance flows from a block's successors back to
it, and successors mostly have higher ids, so each pass moved the sets back
by about one block: a long program needed about as many passes as it has
blocks, each costing O(blocks^2). recomputeAnalyses runs it after every
split of splitSharedMergeBlocks, up to four times per block.

Visit the blocks in post-order of the CFG (successors first), then any the
entry does not reach. The sets start from every block and only shrink, so
the iteration still converges to the same greatest fixed point, now in a
few passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:40:08 +05:30
raghav314 7638ade79f fix(agc): render into 1D color targets as one-row 2D targets
CB_COLOR_ATTRIB3.RESOURCE_TYPE 0 is a 1D surface (AddrResourceType
ADDR_RSRC_TEX_1D in addrlib). On GFX10, addrlib allows a 1D surface the
linear and render swizzle modes (Gfx10Rsrc1dSwModeMask) and picks its
swizzle pattern the same way as for a 2D surface (GetSwizzlePatternInfo
only tells 3D apart). So a 1D color target one row high is laid out
exactly like a 2D target one row tall, and is decoded as one.

A 1D target with a standard swizzle mode is rejected as invalid; one
with more than one row is not modeled and is rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:40:08 +05:30
Dean d9484c719b
Merge pull request #2099 from oneandonlydean/fix/spirv-headers-test-includes
fix(tests): add SPIRV-Headers to the tests that include VulkanTestDevice.hpp
2026-10-09 22:07:10 +13:00
boykopovar 49c27caf55
Merge pull request #2113 from boykopovar/ci/public-lint-gated-builds
ci(build): require manual full builds and auto-test relinker for contr
2026-10-09 12:02:35 +03:00
boykopovar 0ab2a04dd7 ci(build): require manual full builds and auto-test relinker for contributors 2026-10-09 11:58:02 +03:00
Karan Vora 809178603f perf(shader): skip the tiny product check that a constant factor settles
With f32 denormals flushed, every f32 multiply and fma checks whether the
exact product is below 2^-126 (#1850): two exponent extracts, a 32-bit
significand multiply-high and a chain of compares and selects. When a
factor is a literal or inline constant, its exponent settles the check
during translation:

- a factor that is zero (after the input flush), infinite, NaN or at least
  1 in magnitude never gives a tiny product, so the check is not emitted;
- a power-of-two factor never carries out of the significand product, so
  the multiply-high is not emitted.

Constant sources are folded with their abs, neg and denormal flush, so the
factor reaches the check as a constant.
2026-10-09 04:39:22 -04:00
Karan Vora d7007db4dc perf(shader): drop denormal flushes of values that can't be denormal
With f32 denormals flushed, every f32 result is flushed when it is
written and every f32 source when it is read, so a source computed by an
earlier flushing op is flushed twice. A flush returns any value that is
not a denormal unchanged, and the driver can't tell that the first flush
already removed them.

DenormalFlushEliminator replaces a flush whose source can't be a
denormal with the source: a flush, a normal or zero constant, a sign
change, absolute value, clamp or bit cast of such a value, an integer or
f16 converted to f32, and a select or phi of such values.
2026-10-09 04:39:16 -04:00
Dean Galvin 37bc6f2e74 fix(tests): add SPIRV-Headers to the tests that include VulkanTestDevice.hpp 2026-10-09 21:29:22 +13:00
Dean 6cc0503dac
Merge pull request #1550 from ska2704/fix/progress-exclude-test-sources
fix(progress): exclude library test fixtures from function counts
2026-10-09 21:04:18 +13:00
Dean b38abc0a69
Merge pull request #1774 from 011010/test/guest-intel-trampolines-e2e
test(relinker): execute the guest Intel trampolines end to end
2026-10-09 21:04:06 +13:00
Dean a3475ee450
Merge pull request #1563 from krishnaraya4/test/agc-pin-int64-atomics-fail-emit
test(agc): pin the 64-bit atomics emission failures
2026-10-09 21:04:02 +13:00
Dean 25f1008710
Merge pull request #1558 from krishnaraya4/test/agc-target-has-capability
test(agc): check device capabilities by name in the execution tests
2026-10-09 21:03:59 +13:00
Dean 943bd52616
Merge pull request #1514 from CyanBook/docs/drop-json2-value-clear-debt
docs(debt): drop sce::Json::Value::clear from PPSA23566 unknown signatures
2026-10-09 21:03:55 +13:00
Dean 7988ed27c9
Merge pull request #1510 from Kikoarl/fix/unique-test-temp-paths-cpu-topology-icon
test: give cpu topology and icon resource temp paths a random suffix
2026-10-09 21:03:51 +13:00
Dean 69363a01ea
Merge pull request #1428 from NahuelGenchi/fix-flip-compute
test(agc): match the unreadable-code error and run the flip compute mode in ctest
2026-10-09 21:03:47 +13:00
Dean 0905b51f6a
Merge pull request #1931 from johnmaia/feat/videodec2-hevc-vp9
feat(libSceVideodec2): decode HEVC and VP9
2026-10-09 21:03:44 +13:00
Dean 31ca81bfc3
Merge pull request #1910 from TheAggie/fix/pad-vibration-mode-compatible
fix(pad): accept the compatible vibration mode
2026-10-09 21:03:40 +13:00
Dean f97205908a
Merge pull request #1828 from LeandroLP23/test/patched-libraries-load
test(libs): load every patched library with its imports bound
2026-10-09 21:03:35 +13:00
Dean eaed9371ce
Merge pull request #1820 from hugodearaujo/fix/audioout2-main-port-formats
fix(audioout2): match measured MAIN port format validation
2026-10-09 21:03:31 +13:00
Dean 6a7f40514d
Merge pull request #1771 from TideOPL/pr/savedata-mount-status
fix(savedata): report a CREATE2 mount of an existing save as not created
2026-10-09 21:03:27 +13:00
Dean e4492fac50
Merge pull request #1712 from LuisBiceps/test/libc-guest-errors-thread-errno
test(libc): reset errno after the worker thread in guest_errors
2026-10-09 21:03:23 +13:00
Dean cb6d833295
Merge pull request #1705 from muhzain05/fix/ult-finalize-busy
fix(ult): reject finalize with outstanding ulthreads
2026-10-09 21:03:19 +13:00
Dean 812c86cde7
Merge pull request #1481 from awake-devel/feat/http-auth-info-callback
feat(http): accept sceHttpSetAuthInfoCallback
2026-10-09 21:03:15 +13:00
Dean 3e66276cba
Merge pull request #1367 from Raghav314/fix/videoout-window-at-start
fix(videoout): create the window and the device when VideoOut starts
2026-10-09 21:03:10 +13:00
Obi Newman 881fb01069
feat(libs): report Http2, Ssl and Net memory pool statistics (#1119)
sceHttp2GetMemoryPoolStats, sceSslGetMemoryPoolStats and
sceNetGetMemoryPoolStats threw. PPSA16064 (Minecraft Dungeons II,
Unreal Engine) queries all three while its HTTP module starts, and
aborted there.

Each library now records the pool size given at sceHttp2Init,
sceSslInit or sceNetPoolCreate and reports it with a peak and current
use of 0: the offline Http2 and Ssl models and the host-socket Net
library allocate nothing from these pools. The layouts follow the PS4
SDK's *MemoryPoolStats structures. Net returns EBADF for an unknown
pool and EINVAL for a null output, like its other pool calls; Http2 and
Ssl throw for both, as their error codes are unknown. Terminating a
context or destroying a pool forgets its size.

sceHttp2SetResolveRetry, which the title calls next, accepts and
ignores its value like the other Http2 settings. The four Http2
WebSocket exports the title imports are added as unimplemented.

guest_http2, guest_ssl and guest_sce_net check the reported sizes;
guest_sce_net also checks the null-output and unknown-pool errors.
2026-10-09 21:03:06 +13:00
Dean d3a926ad36
Merge pull request #2077 from johnmaia/feat/np-entitlement-info-list
feat(libSceNpEntitlementAccess): report signed out for entitlement info lists
2026-10-09 21:03:01 +13:00
Dean bf65cfb2be
Merge pull request #2004 from NahuelGenchi/feat/json2-object-empty
feat(libSceJson2): implement sce::Json::Object::empty
2026-10-09 21:02:56 +13:00
Dean a04350ae25
Merge pull request #1861 from fisherjoey/fix/ajm-atrac9-multichannel
fix(ajm): decode multichannel ATRAC9 streams
2026-10-09 21:02:52 +13:00
Dean d51e8f020a
Merge pull request #1838 from LeandroLP23/feat/net-resolver-multiple-records-ex
feat(libSceNet): implement sceNetResolverStartNtoaMultipleRecordsEx
2026-10-09 21:02:48 +13:00
Dean 9e8db341d8
Merge pull request #1775 from MathiasDevelopes/fix/libscehttp-wait-request
fix(libSceHttp): sceHttpWaitRequest reports no ready requests
2026-10-09 21:02:43 +13:00
Zheorgyan 688df0b880 test(libc): wait for std::async thread teardown in host_thread_local 2026-10-09 09:45:21 +02:00
Dean Galvin c8c90995a0 fix(shader): match half-wave reductions in vertex programs
A program's entry EXEC is the ballot of !gl_HelperInvocation in a pixel program and the ballot of true in vertex, local and tessellation programs (emitEntryPrologue). The half-wave reduction matcher only accepted the pixel form, so a wave64 vertex program that scans keys selected under its EXEC and reads lane 63 threw that the lane is outside the 32-lane host subgroup.

EntryLaneWalk now also accepts a ballot of true as within the entry EXEC for those stages. Every invocation is live at their entry, and a later ballot of true holds only invocations that are still active. Pixel programs keep the !gl_HelperInvocation form, because a ballot of true there includes helper invocations. Compute and mesh programs keep their own form too, because their entry EXEC can bound the local invocation index.
2026-10-09 20:36:07 +13:00
Dean Galvin ac2d172e0b perf(agc): bind misaligned draw buffer regions in place through the view adjustment
A draw's guest buffer region inside a host import at an offset off
minStorageBufferOffsetAlignment was copied per build (a new buffer, an
input snapshot, a vkCmdCopyBuffer that ends the open render pass), and
DirectRegions refused such builds as templates.

Descriptor already binds any DWORD-aligned view from the aligned offset
below it and passes the remainder through the shader's memory offset
slot. A draw build that is not address-based and whose every guest buffer
element has such a slot (a push constant byte, or a shader data byte
inside its data buffer) now binds a region whose offset in its import is
DWORD aligned in place, like an aligned one: its read-only views are
snapshotted per draw by PrepareDrawBindings at address - adjustment, the
import serial keys the template, and Revalidate proves it per use.
Dispatches keep the copy (they read in-place inputs at execution, not at
record).

agc_driver_recorder_tests misalignedRegionTests: a misaligned read-only
draw region is read in place, the build is reusable, the push constant
carries the adjustment, and the per-draw snapshot starts at the aligned
offset below the view.
2026-10-09 20:36:07 +13:00
Dean Galvin 954864ea80 perf(agc): keep up to 1024 cached pipelines
CachedPipeline keeps at most 256 pipelines. A level with a larger working
set thrashes the LRU: every miss creates a new VkPipeline (modules,
layout, render pass and a driver compile from the pipeline cache). The
bound is now 1024. A cached pipeline is a pure function of its key, so
the bound changes only memory and time.
2026-10-09 20:36:07 +13:00
Dean Galvin 8a58185306 fix(shader): prove half-wave reduction keys through selected and merged lane bits
The half-wave reduction read (v_readlane_b32 of lane 31 or 63 after a DPP row scan) is exact on a narrower host subgroup only when the scan's keys are the identity outside the entry EXEC. EntryLaneWalk::ZeroBit now also proves that through a constant false, a SelectU1 whose two values both prove it, and a bool Phi whose inputs all do. A mask written inside a divergent branch reaches the key select in that form, so such a scan threw that lane 63 is outside the 32-lane host subgroup.
2026-10-09 20:36:06 +13:00
Dean Galvin 24876afca9 fix(agc): draw nothing for resummarize draws without depth or color work
A draw with DB_RENDER_CONTROL.RESUMMARIZE_ENABLE recomputes the HTILE summary of the bound depth surface from its depth values. HTILE is not modeled, so such a draw with depth and stencil tests off and no color writes changes no modeled state. It now passes the maintenance check and draws nothing, instead of throwing. Resummarize draws with depth, stencil or color work, and copy and decompress draws, still throw.
2026-10-09 20:36:06 +13:00
LeandroLP23 06f78c2030 test(libs): load every patched library with its imports bound
ctest loads the libraries from libs/unpatched, so an import that nid_patcher
renames out of another library's exports only shows when a title loads the
patched prx. patched_libraries loads each patched .prx with LoadLibraryEx on
Windows and dlopen(RTLD_NOW) on Linux, and depends on the libs target so the
patched files are current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:05:19 +02:00
john.maia 530aa2088b feat(libSceNpEntitlementAccess): report signed out for entitlement info lists
The unified and service entitlement info list requests and polls threw.
They now return SCE_NP_ERROR_SIGNED_OUT, like the consume requests in
the same library. Their signatures are unknown, so they stay declared
without parameters.

PPSA15657 calls the unified request during start-up and continues past
the error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134RWCyiyydJBbfKz8g9Bwe
2026-10-09 07:56:44 +01:00
jdmagic 9d2e4188ca feat(libs): provide the exports PPSA01289 imports that no library has
Sackboy: A Big Adventure (PPSA01289) imports nine functions that no library
exports, so eager binding fails before it starts.

- libSceVoiceChat: sceVoiceChatRequestLeaveVoiceChatGroup and
  sceVoiceChatRequestDeleteVoiceChatGroup, offline requests like the other
  sceVoiceChatRequest* calls
- libSceNpSessionSignaling: sceNpSessionSignalingGetConnectionFromPeerAddress,
  a throwing stub; the signature is unknown
- libSceCdlgG2P, a new library: the six sceG2PDialog* functions, throwing
  stubs declared without parameters

TechnicalDebt records the assumed and unknown signatures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 02:42:57 -04:00
LuisBiceps a551d3ee36 fix(libSceSystemService): match RommPS's web browser signature and test any arguments
The param is void*, as RommPS declares it. The test also passes a null and an empty URI and a param that must stay untouched, and compares against 0x8002002D itself. The debt entries now say the error is returned for any arguments and that the param layout and the console's argument checks are unknown.
2026-10-09 14:40:31 +08:00
jdmagic 90864ffb8d feat(libSceAudioOut): accept sceAudioOut2MasteringTerm
PPSA01289 (Sackboy: A Big Adventure) calls sceAudioOut2MasteringTerm when it
replaces its world, which threw. Like Init and SetParam it has no effect, as
there is no mastering stage. The title creates its next world's audio device
before it destroys the previous one, so Init runs twice before Term runs
twice; whether the console reports an error for either is unknown, so both
return 0 and the case is recorded in TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 02:40:20 -04:00
LuisBiceps 9f7e2ca75d feat(libSceSystemService): report the web browser as unavailable
sceSystemServiceLaunchWebBrowser fails with the kernel's EOPNOTSUPP: there is no web browser to open. RommPS PPSA76677 stops on main at this import and shows a QR code instead when the browser does not open.
2026-10-09 14:31:04 +08:00
jdmagic 8ae350caaa fix(libSceAmpr): sceAmprCommandBufferClearBuffer returns the detached buffer
sceAmprCommandBufferClearBuffer detaches a command buffer's memory and
returns it so the caller can free it. It returned 0. PPSA01289 (Sackboy: A
Big Adventure) frees the result after every streaming read, so each read
leaked its 16 KiB command buffer until the allocator ran out of memory
during the first world load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:58:38 -04:00
Scott Schuster af9e60b690 fix(agc): accept RADV's point and line depth bias enable on triangle draws
With depth bias enabled, RADV sets POLY_OFFSET_PARA_ENABLE in
PA_SU_SC_MODE_CNTL next to the front and back enables, whatever the
topology; vkQuake's draws carry 0x3a46. The bit applies the offset to
points and lines, so it changes nothing for triangles, and Vulkan applies
depth bias only to polygons. It is now accepted with depth bias on
triangle topologies; point and line draws with it are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:54:22 -05:00
Aryan Sharma 631654b649 perf(libc): limit the TZ initializer to Linux 2026-10-09 11:16:57 +05:30
Alex c9ab6a72a5 fix(agc): store labels the GPU cannot reach in stream order
A label in memory the device has no host import of was stored when its
batch was reaped, after later labels the GPU had already made visible.
A title that reused that memory saw its next command buffer overwritten
by the stale value (#1458). Wait for the recorded work and store it then.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 01:42:59 -04:00
Aryan Sharma 7b130700f6 feat(libc): implement malloc_stats_fast through the application allocator
A title that replaces the allocator through its libc parameters also
supplies malloc_stats_fast in that table, and PPSA28997 calls it. It is
now forwarded to the title's function. Without a replacement allocator
that provides it, the call throws.
2026-10-09 11:04:45 +05:30
Aryan Sharma 11b32af522 perf(libc): set TZ once on Linux
Without TZ, glibc's localtime and mktime run tzset on every call and
re-check /etc/localtime each time. PPSA28997 calls them every frame
during its intro, which then spent most of its time there. TZ is set
to :/etc/localtime when unset, so the zone is read once.
2026-10-09 10:59:48 +05:30
Alex 254f354e72 fix(shader): flush v_div_fixup_f32 src1 and src2 denormals
With f32 denormals flushed, as in the 0xc0 float mode titles use, the
hardware flushes the denominator and numerator of v_div_fixup_f32 but
keeps a denormal quotient and result. The recompiler kept all three,
so a denormal divisor gave the quotient back instead of an infinity.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 01:19:28 -04:00
Arvind Frøiland 7fc025e1c8 test(agc): check MSAA storage emission without the device's support
PrepareMultisampledStorage only inspects the SPIR-V that the recompiler
emits for multisampled storage writes and atomics, but it took its
target from the device, so on a device without
shaderStorageImageMultisample, such as MoltenVK, the emission failed
and agc_driver_prepared_shaders failed in all its variants. The target
now has the StorageImageMultisample capability, and the check that a
target without it is refused still removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:06:13 +09:00
Nahuel Genchi 5c291a5557 fix(agc): read an unwritten pixel program address as unset
PixelProgramSkipped only treated SPI_SHADER_PGM_LO/HI_PS written as 0 as
a draw without a pixel program, while the draw decoder already reads an
unwritten address as 0 and binds the null pixel program for it. A
depth/stencil-only draw whose pixel program address was never written
was instead rejected by the precheck with "depth/stencil-only draws
without a pixel shader are not implemented".

An unwritten address is now unset in PixelProgramSkipped too, so such a
draw goes through the null pixel program like one with the address
written as 0, and one that writes color is rejected as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 02:05:48 -03:00
Alex f4131a546b fix(shader): clamp packed f16 min/max signaling NaN results to zero
With IEEE=1, v_pk_min_f16 and v_pk_max_f16 return a quieted NaN for a
signaling NaN operand, and DX10_CLAMP=1 clamps it to +0. The clamped
form skipped the bit-level NaN selection and saturated the driver's
min/max, which returns the other operand, so it gave that operand.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 00:43:35 -04:00
Nahuel Genchi b9d7ff46d2 feat(libSceJson2): implement sce::Json::Object::empty
Sonic Origins (PPSA05324) imports sce::Json::Object::empty() const
(i2l3IYvQ9UE) and fails to load without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:33:58 -03:00
LuisBiceps 75345b07b9 test(libSceSystemService): reject app ID 0 and how -2 in the kill test
Also say in the debt entry that on the console sceSystemServiceKillApp returns and the shell ends the title, while here the call does not return.
2026-10-09 12:22:29 +08:00
LuisBiceps 38cbdfe34c fix(libSceSystemService): close the title through the libc exit coordinator
sceSystemServiceKillApp now ends the title as guest exit() does, so driver calls that wait for the exit park instead of throwing ProcessShutdown, and a second exit waits for the first. The test now fails when the kill returns, exits with a status other than 0 or bypasses the coordinator, and checks why a rejected call throws.
2026-10-09 12:21:09 +08:00
LuisBiceps cb43a4c306 feat(libSceSystemService): let the running title close itself with sceSystemServiceKillApp
Report an app ID for the running title from sceSystemServiceGetAppIdOfRunningBigApp, and shut the guest down and exit when sceSystemServiceKillApp receives that ID with the arguments -1, 0 and 0. SwanStationPS5 (PPSA98510) 1.0.6 closes itself this way and stops on both imports on main.
2026-10-09 12:10:19 +08:00
Scott Schuster 1e5b8d9e7c fix(shader): report a truncated memory, image or export instruction as out of range
ReadRawComputeShader decodes a growing prefix of guest memory and reads
more when the decoder throws std::out_of_range, which the vector, scalar
and instruction-length checks throw for an instruction cut off by the end
of the span. The memory (SMEM, DS, MUBUF, MTBUF, FLAT), image and export
decoders threw std::runtime_error instead, so a two-word instruction
across a window boundary failed the read: vkQuake terminated on "truncated
FLAT instruction". These now throw std::out_of_range too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:02:17 -05:00
LuisBiceps b38c8d6ae8 fix(agc): correct the default tessellation factor ring address
The hardware findings give 0xF_F000_0000, which is 0xFF0000000, not 0xFF00000000. Check the ring across threads, at ps5-opengl's size of 0x1b000 and with a canary after the outputs, and say in the debt entry that nothing is written to the ring.
2026-10-09 11:45:53 +08:00
David d658f73e00 fix(tools): decode overlap command output as UTF-8 2026-10-08 20:40:46 -07:00
LuisBiceps d8ecb8e4eb feat(agc): implement sceAgcDriverGetTFRing
Record the tessellation factor ring that sceAgcDriverSetTFRing receives and report it from sceAgcDriverGetTFRing, with the console's default of 0xFF00000000 and 128 KiB before a title sets one. VITA5 (PPSA39410) and Homebrew UI Lab (PPSA99050) stop on this import once sceVideoOutGetResolutionStatus resolves.
2026-10-09 11:37:05 +08:00
Liav Mordouch e6eb64aa58 fix(shader): reduce v_sin_f32 and v_cos_f32 inputs exactly
v_sin_f32 and v_cos_f32 take their input in cycles, and the SPIR-V
backend reduced it with GLSL Fract before scaling by 2*pi. For x in
(-0.5, 0), fract(x) = 1 + x is rounded to a multiple of 2^-24, which
drops the low bits of x, and for |x| <= 2^-25 it rounds to 1.0, which
RADV's v_fract_f32 clamps to 0x3f7fffff. On RADV, v_sin_f32(-2^-30)
returned 0xb4c90fde (-3.7e-7) where RDNA3 returns 0xb1c90fd5 (-5.9e-9).

The cycle is now x - roundEven(x). It lies in [-0.5, 0.5] and is exact
for every finite x: it is x when roundEven(x) is 0, and Sterbenz's
lemma applies otherwise. Finite inputs of magnitude 2^23 or more still
reduce to +0, so the select that forced them to 0 is removed. Infinite
and NaN inputs are unaffected: the translation selects their results
on the input bits.

Measured on RDNA3 (gfx1101) with the hardware oracle, with the same
results in all 16 combinations of IEEE, DX10_CLAMP and the f32 and f16
denormal modes: over 544 inputs, v_sin_f32(x - v_rndne_f32(x)) returns
the bits of v_sin_f32(x) for 519 and is at most 11 ulp off, while
v_sin_f32(v_fract_f32(x)) matches 403 and is more than 16 ulp off for
80, all of them in (-0.5, 0). For v_cos_f32 the counts are 523 (at
most 7 ulp off) and 484 (6 more than 16 ulp off). On RADV the
recompiled shader returns the bits of the v_fract_f32 sequence before
this change and of the v_rndne_f32 sequence after it, for all 544.

v_sin_f16 and v_cos_f16 share the reduction. On RADV, with f16
denormals kept, v_sin_f16 now returns the RDNA3 bits for all 65536
inputs, where it was 1 ulp off for 6 small negative ones, and
v_cos_f16 matches for all of them before and after.
2026-10-09 06:34:59 +03:00
Alex 33603bf8a9 fix(shader): keep runtime image mode switches inside continue targets
An image with several runtime modes is emitted as a switch whose default
and disabled modes end in OpUnreachable. In a loop latch that exit breaks
the continue construct, and spirv-val rejected the shader. Inside a
continue target those cases now join the merge with an undefined result.

Fixes #1921

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 23:05:07 -04:00
Alex dc902b2eae fix(hw-oracle): assemble wave64 bodies in wave64 mode
clang assembled every body as wave32, so a --wave64 body that used vcc
or an SGPR pair as a condition failed with "operands are not valid for
this GPU or mode". Pass -mwavefrontsize64 on wave64 runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 23:03:22 -04:00
Liav Mordouch 7ba9807147 fix(shader): read v_ldexp_f16 src1 float inline constants as f16
v_ldexp_f16 read src1 with readU32, so a float inline constant gave
the low 16 bits of its f32 pattern: 0 for 0.5, 1.0, 2.0, 4.0 and
their negatives, which returned src0 unchanged, and 0xf983 for
1/(2*pi), which clamped to -64 and returned a signed zero. The
hardware treats src1 as an f16 operand, as LLVM's
LDEXP_F16_VOPProfile in VOP2Instructions.td records, so it receives
the f16 encoding: 0.5 is 0x3800, an exponent of 14336. Measured on
gfx1101, ldexp(1.0, 0.5) is +inf and ldexp(1.0, -0.5) is +0.

Read VOP3 src1 through readF16SourceBits, which maps the float inline
constants to their f16 bits and reads other operands as before.
Registers, integer inline constants and literals already matched the
sign-extended low 16 bits the hardware uses. SDWA src1 keeps its old
read, as gfx11 has no SDWA to measure it on.
2026-10-09 05:53:32 +03:00
Renan Pires 851f3b7a10 feat(libkernel): implement getrlimit for RLIMIT_DATA 2026-10-08 23:52:33 -03:00
Renan Pires 942a105c39 feat(libkernel): implement pthread_getcpuclockid and per-thread CPU clocks 2026-10-08 23:50:03 -03:00
Liav Mordouch ccef16b4da fix(shader): return +0 when v_div_fmas_f32 cancels with |src2| >= 2^64
With VCC set and a src2 exponent field of 128 or more (scale 2^64),
v_div_fmas_f32 recomputed an fma result with exponent field 0 as an
fma of the smaller multiplicand times 2^64, the other multiplicand and
src2 * 2^64. For |src2| >= 2^64, src2 * 2^64 overflows to infinity, so
an fma that cancels exactly returned -inf or +inf. The hardware
returns +0: measured on gfx1101 for (1.0, FLT_MAX, -FLT_MAX) and
(1.0, -2^100, 2^100) in all 16 combinations of IEEE mode, f32 and
f16/f64 denormal mode and DX10_CLAMP.

Only exact cancellations reach that path. With |src2| >= 2, a nonzero
sum below 2^-126 needs a product above 1, which is a multiple of
2^-47, while src2 is a multiple of 2^-22, so a nonzero sum is at least
2^-47 and the fma result is normal. The scaled result is then the fma
result times 2^64, +0 for a cancellation. The recomputation is now
done only for the 2^-64 scale, when the fma result overflows.
2026-10-09 05:49:01 +03:00
SK Arin 567b1f923f chore(oracle): resolve upstream test registration conflict 2026-10-09 07:55:35 +05:30
Liav Mordouch df5c0ec35c test(shader): check v_fma_mix_f32 in FmaRounding
FmaRounding checks v_fma_f32, v_fmac_f32, v_fmaak_f32 and v_fmamk_f32
against the fused result on the GPU, but not v_fma_mix_f32. It now
also runs v_fma_mix_f32 v20, v4, v5, v6 with all sources f32 on its 64
rows and expects the fused value, in the group that is skipped when the
device splits fma.
2026-10-09 05:20:42 +03:00
Raihan Abdul Majid c8c2079e56 fix(agc): sample resident depth surfaces when a stage-A texture record hits
fastTexture took the Textures() cache entry of a stage-A image record
without asking whether a depth surface is resident at the address. The
full lookup in cachedTexture returns DepthSurfaceTexture first; the fast
path skipped it, so once a guest-memory entry existed for a depth
target's descriptor, every later sampled read got that entry and saw
the guest memory under the target, which a depth target never writes.
The fast path now returns nothing while a depth surface is resident
there, and the lookup falls back to cachedTexture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
2026-10-09 09:15:28 +07:00
arcwiser 2051436d4c test(shader): cover high MIMG opcode bit 2026-10-09 13:06:21 +11:00
arcwiser 3058b5193b fix(shader): name unsupported MIMG opcodes 2026-10-09 12:43:37 +11:00
TacoCat055 9a6667cb4c docs: explain relinker Python test discovery 2026-10-08 19:27:23 -06:00
Joey Fisher 21612855b3 fix(agc): skip registration-time preparation for unsupported shader types 2026-10-08 19:16:19 -06:00
Zinebyte 2381e7fc64 fix(relinker): reject prefixed system-call instructions
Use the decoded opcode offset when checking forbidden system calls.
Add synthetic regressions for prefixed forms, immediate decoys, and the skip option.

AI-assisted: Codex. The submitting author is responsible for every changed line.
2026-10-08 20:34:40 -04:00
john.maia f5293b64d2 feat(libSceVideodec2): decode HEVC and VP9
EVO-PLAYER (PPSA99039) creates resident AVC, HEVC and VP9 decoders at
start-up, and stopped at "Videodec2: unsupported codec" on the HEVC one.
Codec types 974921 (HEVC) and 2382845 (VP9) now open FFmpeg's HEVC and
VP9 decoders. HEVC input goes through the same Annex B conversion as
H.264 and VP9 frames are passed through; output stays 8-bit NV12, and a
frame deeper than 8 bits throws. Picture info throws for HEVC and VP9,
whose layouts differ from the AVC one.

Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
2026-10-09 01:27:15 +01:00
Joey Fisher def0be1085 fix(agc): prepare a rect-list draw's missing rectangle at draw from its prepared stages 2026-10-08 18:06:04 -06:00
Joey Fisher a2dc28aa6a refactor(agc): look up a rect-list draw's rectangle through DrawRectangle 2026-10-08 18:01:42 -06:00
Scott Schuster 88cc2ea477 fix(agc): accept RADV's disabled conservative rasterization state
With conservative rasterization disabled, RADV programs
PA_SC_CONSERVATIVE_RASTERIZATION_CNTL to NULL_SQUAD_AA_MASK_ENABLE alone,
where libSceAgc writes the two INNER_TO_NORMAL overrides (0x6000). A value
made of only those bits now decodes as disabled; overestimation (0x6001) keeps
its checks, and every other mode is still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:47 -05:00
Scott Schuster 6c5b181b68 fix(agc): accept PA_SC_MODE_CNTL_1's out-of-order watermark
RADV sets OUT_OF_ORDER_WATER_MARK to 7 on every GFX10 draw, also when
OUT_OF_ORDER_PRIMITIVE_ENABLE is off. The watermark only tunes out-of-order
rasterization, which stays rejected, so the field is accepted alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:47 -05:00
Scott Schuster 1e20b4ec50 feat(agc): blend against an opaque destination for CB_COLOR_ATTRIB FORCE_DST_ALPHA_1
FORCE_DST_ALPHA_1 makes blending read a target's destination alpha as 1, as
for an RGBX surface; RADV sets it for formats without alpha. The target's
blend factors are rewritten to what they become with Ad = 1: DST_ALPHA is
ONE and ONE_MINUS_DST_ALPHA is ZERO, SRC_ALPHA_SATURATE is ZERO in the color
equation, and DST_COLOR and ONE_MINUS_DST_COLOR are ONE and ZERO in the
alpha equation. Other CB_COLOR_ATTRIB bits stay rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:46 -05:00
Scott Schuster 4bc84d6b44 fix(relinker): convert stack-guard and thread-pointer reads with an empty PT_TLS
A title built with -fstack-protector reads its guard from fs:0x28 even when
it has no thread-local data and its linker emits an empty PT_TLS. The
Windows TLS builder refused any guest TLS access in that case. The guard and
the thread pointer live in the thread control block, which the builder
already emits, so an empty PT_TLS now takes the normal path, where a
zero-sized TLS block still rejects every other displacement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:08:06 -05:00
Scott Schuster 7c8dae0b33 fix(pad): accept the compatible vibration mode
scePadSetVibrationMode rejected mode 2 (compatible, per SharpProspero's
ScePadVibrationMode). The PS5 SDL joystick driver requests it on every
open and closes the pad when it fails, so SDL titles lost their controller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:08:05 -05:00
Joey Fisher 1f0060d72d fix(shader): saturate VOP3 v_add/sub_nc_u32 and 16-bit add/sub on clamp 2026-10-08 16:55:06 -06:00
Joey Fisher 485387ef2f test(shader): pin VOP3 integer add/sub clamp results measured on RDNA2 2026-10-08 16:55:06 -06:00
krishnaraya 17f1a2e59a test(agc): pin the 64-bit atomics emission failures
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 18:28:50 -04:00
krishnaraya e5da5fd2a3 fix(agc): lay out 3D SW_64KB_D_X textures as thick volumes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 18:28:19 -04:00
krishnaraya b719eedaa5 fix(agc): round linear volume mip extents up as addrlib does
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 18:28:18 -04:00
krishnaraya 96569aac30 fix(shader): refuse the MUBUF lds modifier instead of decoding a VGPR load
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 18:28:16 -04:00
Celegans12 d3a66dbbbe feat(agc): implement deferred faults for descriptors read through null SRT pointers
Capturing a shader evaluates every V#, T# and S# the program uses,
including those behind a branch the wave does not take. When such a
descriptor was loaded through a pointer read from memory that is null
or unmapped, the capture threw "guest memory is not readable", while
the console faults only if a wave executes that s_load. The descriptor
now reads as zero words, and the flat SRT walk records the s_load's
dwords as it does for flat reads, so their guarded ReadConst raises
the BDA fault where the wave runs the s_load. A zero V# is an absent
buffer and a zero T# binds a null descriptor, as for any zero word
read from memory, so nothing new enters a key. A zeroed descriptor
whose read no flat slot records still throws, as do branch conditions,
uniform fills, table bases and user-data pointers.
2026-10-09 00:21:00 +02:00
Celegans12 56f8a62428 feat(agc): implement deferred faults for reads through null SRT pointers
Capturing a shader threw "null or misaligned address" when the flat
SRT walk read through a pointer loaded from memory that is null or
unmapped, even when the program skips that s_load. Such a read now
yields zero and a record with its pc and address, as does a slot whose
address needs it. The registered artifact checks one flag word per
guarded slot at each ReadConst; the capture appends the flags and the
records to the flattened SRT, and a set flag raises an Unmapped BDA
fault through the fault buffer and stops the invocation as a BDA read
does. Nothing per capture enters a key: poisoned and clean captures
share one variant and specialization. Descriptors, branch conditions,
uniform fills, table bases and user-data pointers that need such a
value still throw, and poisoned results stay out of the dispatch and
draw caches. The shader disk cache format becomes 21.
2026-10-09 00:20:59 +02:00
overlordxrz-source 8f09ec3616 feat(libkernel): implement system 2026-10-08 18:15:49 -04:00
LeandroLP23 f054374661 test(libSceNet): pin the resolver info layout and check the buffer on errors
The layout offsets the titles read are static_asserts, and guest_sce_net now
checks a canary past byte 384, distinct records, and an untouched buffer on the
EINVAL, RESOLVER_ENODNS and EBADF paths, as #1845's test did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:58:18 +02:00
LeandroLP23 427fd92591 feat(libSceNet): implement sceNetResolverStartNtoaMultipleRecordsEx
PS5VR (PPSA99177) stops at start-up on the unresolved import sT4nBQKUPqM;
Jelly5, Emby5 and Nuvio import it too. The call fills the 384-byte resolver
info with up to ten IPv4 records (32 bytes each, family at +16) and the record
counts at +320 and +324, from the same host lookup sceNetResolverStartNtoa
uses, now shared. Only flags 0 is implemented; other flags throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:52:02 +02:00
LeandroLP23 7449e51483 feat(libc): implement __inet_aton
PICO-8 for PS5 (PPSA99808) stops at start-up on the unresolved import
a7ToDPsIQrc from libSceLibcInternal. The parser follows FreeBSD's inet_aton
(lib/libc/inet/inet_addr.c): one to four parts in decimal, octal or hex, the
last part filling the remaining bytes, input ending at a NUL or whitespace,
and a null address only validating.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:48:48 +02:00
Gerard L. 1d6968225f test(agc): run agc_driver_mesh_tests under ctest
The mesh test was built only on request and never registered, so the
translation of NGG geometry programs to mesh shaders ran in no test
run. On an RTX 4060 it passes. Register it with the other AGC driver
tests.

Three cases would fail or mislead under ctest. Without a Vulkan device
the test failed, and the Windows job has none. A device without
VK_EXT_mesh_shader exited 0, so ctest reported a pass for a test that
drew nothing. On llvmpipe, with the Linux job's Mesa 25.2.8 and Ubuntu
24.04's LLVM 20.1.2, every draw that builds a mesh pipeline stops the
process with "LLVM ERROR: Cannot emit physreg copy instruction"; Mesa
26.2.4 with LLVM 23.1 segfaults in LLVM's code generation instead. The
SPIR-V of all 18 modules the test builds passes spirv-val. Mesa #14376
reports the same error for lavapipe mesh shaders that index shared
memory per invocation; that the cause is the same is not established.

The test now opens its device with OpenVulkanTestDevice and exits 77
without a device, without VK_EXT_mesh_shader and on llvmpipe, saying
why. ANYPS5_REQUIRE_VULKAN still turns a missing device into a
failure. The Linux job therefore skips the test; it runs on hosts with
a GPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:44:46 +02:00
Joey Fisher 24623021cd fix(ajm): decode multichannel ATRAC9 streams
Config 0x30 (the ambisonic layout, 4 to 16 channels) was rejected at instance init, so Demon's Souls asserted in
its audio player and crashed entering the tutorial level. Each channel is decoded as a mono stream and the
blocks are interleaved.
2026-10-08 15:44:01 -06:00
sarohy f765b27cc0 test(relinker): cover CLI argument parsing
Cli::ParseArgs had no test coverage: its only sibling test
(AutorunExitTests) exercises the autorun launcher, not the parser.

Add cli_args_tests covering every option and its side effects, the
--rpath and --exclude-sce-module value consumption (including that the
following token is taken verbatim rather than re-parsed as a flag), the
unused-filter value and single-specification validation, the
--exclude-sce-module/--skip-sce-module conflict in both orders, the
order-independent --windows-diagnostics/--windows-gui requirement on
--windows, unknown-option and extra-positional rejection, and the usage
message when an input or output path is missing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-09 02:40:19 +05:00
Nahuel Genchi 81d86aa523 fix(libc): call the new handler when operator new fails to allocate 2026-10-08 18:36:31 -03:00
journaltraces e411282b80 feat(libc): implement stpcpy
PICO-8 for PS5 (PPSA99808) imports stpcpy from libSceLibcInternal, one
of the absent imports #1578 lists for it. POSIX defines it as strcpy
that returns a pointer to the terminating null of the copy.
2026-10-09 00:22:57 +03:00
journaltraces 668a1e6f72 feat(libc): implement ldiv
RetroArch (PPSA99169) imports ldiv from libSceLibcInternal, one of the
absent imports #1578 lists for it. The guest long is 64-bit, so the
export takes std::int64_t and returns lldiv_t, which has the guest
ldiv_t layout; std::ldiv would truncate on Windows, where long is 32-bit.
2026-10-09 00:22:57 +03:00
ps54all 1bd0ef8c96 refactor(libkernel): share one rename implementation with libc
The repo allows one implementation per export. Move libc's rename into
libc/src/Rename.cpp, compile that file into both libc and libkernel, and
drop the second copy from libkernel's Stdio.cpp. FilesystemError moves to a
header so the shared source can use it.

The test now checks that the symbol it resolves belongs to libkernel (module
handle on Windows, dladdr on Linux) so it fails when the export is removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 23:17:04 +02:00
ps54all 1f580c8dde test(libkernel): use a relative directory in the rename test
The guest VFS on Linux does not map absolute host paths, so the test failed
at the first rename there. Match GuestFilesystem.cpp and build the directory
relative to the working directory.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 23:17:04 +02:00
ps54all 372e2d4267 test(libkernel): cover the libkernel rename export directly
guest_filesystem_tests links libkernel and libc, both of which define
rename_nid_postfix, so which one it binds to depends on the loader and the
suite passes either way. Resolve the symbol from libkernel.prx explicitly so
the export added for titles that ship their own libc.prx is actually tested.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 23:17:03 +02:00
ps54all fc457760a8 feat(libkernel): export the POSIX rename
Titles that ship their own libc in sce_module import rename from
libkernel (NID NN01qLRhiqU), where it was missing, so PPSA12544 failed
to start. It checks both paths like unlink and maps sceKernelRename's
result to errno.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:17:03 +02:00
Prophet069 05e1cf9d67 fix(libc): bridge guest exception vtable callbacks
Give guest exception what, non-deleting destructor and deleting destructor slots explicit APS5_VABI types and register guest adapters. Preserve native helpers, object layouts, native exception routing and existing malloc/free ownership.

Add mismatched and cleared RCX regressions for plain and message vtables, observing actual libc free calls to reject foreign or duplicate frees. Retain typed guest catch/rethrow and native exception coverage. All 27 targeted CTests pass three repetitions on Windows Release; Linux execution remains unvalidated.
2026-10-08 23:06:47 +02:00
Prophet069 a961ad35e5 fix(libc): bridge guest message exception destructors
Guest message throws registered native Windows callbacks even though Release invokes guest callbacks using System V. Register an APS5_VABI adapter in the standard and regex message throw paths and retain the native DestroyMessage helper and legacy callback storage type.

Add MinGW CTest regressions with distinct or zero RCX, shared and final-release messages, typed guest catches, rethrow and normal Release. All ten new cases plus Windows exception and thread callback regressions pass three repetitions. Linux execution remains unvalidated; guest vtables and host exception paths are unchanged.
2026-10-08 23:06:47 +02:00
TideOPL 39463913c7 fix(libScePad): fuse queued pad states at the read time
Keeping lastFuseTime at its maximum never let it recover from a process time that wrapped on the first call (fixed separately in #1501), so tilt correction stopped and guest_pad failed. Queued states keep their own timestamp; the orientation is fused once at the time of the read, as scePadReadState does.
2026-10-08 21:56:33 +01:00
hugodearaujo b7b281678b fix(audioout2): match measured MAIN port format validation
Measured on a PS5 (firmware 13.60) through dlopen of libSceAudioOut.sprx:
a MAIN (type 0) port accepts 1, 2, 8 or 12 channels (bits 8-11) with
sample type 0 or 1 (bits 0-6). Bit 7 without 8 channels returns
0x80268001, any other unsupported format returns 0x8026800E, and both
write UINT64_MAX to the output handle. Bits 12-31 do not affect the
result. Other port types keep their current validation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:41:02 -03:00
eliasbruno124-dev ac2b0f5deb fix(relinker): rebase guest runpaths from their output directories 2026-10-08 22:31:03 +02:00
Jan Šlégl 8f31696450 feat(libkernel): implement socketpair
AF_UNIX pairs as FreeBSD 11 makes them: SOCK_STREAM, SOCK_DGRAM and
SOCK_SEQPACKET with protocol 0, SOCK_NONBLOCK applied to both ends and
SOCK_CLOEXEC accepted, EAFNOSUPPORT for an unknown family, EOPNOTSUPP
for AF_INET and AF_INET6, EPROTONOSUPPORT for type 0 or a protocol,
EPROTOTYPE for another type, EFAULT for a null output, and nothing
written on failure. The ends are guest sockets, so send, recv,
shutdown, fcntl, poll and close work on them; getsockname and
getpeername report the unnamed AF_UNIX address, recvfrom and recvmsg
no address for a stream and the unnamed one for a datagram. On Linux
the pair is the host's socketpair; on Windows a loopback TCP connection
or two connected UDP sockets, and SOCK_SEQPACKET throws. The remaining
differences from the console are recorded in TechnicalDebt.

OpenSSL's QUIC notifier in 15 catalog titles creates such a pair.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 21:51:00 +02:00
st44rplatinum 3599d41941 docs(libSceSystemService): record PPSA01521 as the MediaPlay caller 2026-10-08 22:45:43 +03:00
Jan Šlégl 7785933807 feat(libkernel): implement sceKernelGetFsSandboxRandomWord
Returns the name of the directory under which a title's sandbox exposes
system files, which homebrew SDKs splice into paths such as
/<name>/common/cert/CA_LIST.cer and /<name>/common/lib/libc.sprx. The
name is fixed here; recorded in TechnicalDebt together with the fact
that nothing is mounted under it.

Registers guest_sandbox_random_word.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 21:39:11 +02:00
SilentOne 1b5d406a2f fix(relinker): add regression test for fall-through after zero padding and tighten reset condition 2026-10-09 01:02:14 +05:30
Scott Schuster 8eb2c3d504 feat(agc): detile XOR-swizzled textures whose base carries a pipe/bank XOR
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:30:52 -05:00
SilentOne f8031f7c9e fix(relinker): keep fall-through edge after trailing zero padding in StrictReachability 2026-10-09 00:58:57 +05:30
SilentOne e55209d274 perf(relinker): replace O(n²) zero-padding scan in StrictReachability
addGap and buildEdges each called isZeroPadding(address, end) at every
instruction boundary. isZeroPadding scanned from the current address to
the region end, so the total work for a region with N instructions and a
trailing-zero suffix of length Z was O(N*Z), quadratic in the worst case.

Replace with trailingZeroStart, which scans backwards from the region end
once to find the start of the trailing-zero suffix. The loop then stops at
that position, eliminating the per-instruction zero check entirely.
2026-10-09 00:58:57 +05:30
Chad cd43c270d6 Merge upstream/main into fix/recompiler-descriptor-phi-web
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:17:07 -05:00
gdr-98 21d21da385 fix(libc): format guest wide printf arguments on Linux 2026-10-08 21:15:04 +02:00
Chad f5ba4e9c68 fix(recompiler): throw for descriptor web leaves that are not SRT descriptors
A path whose T# or S# dwords hold a program-counter, EXEC or compare-mask
value is no longer folded onto the first descriptor: the web split gives up
and the read throws as on main. Cache the invariant-Phi resolution per web,
lower the state limit to 512 and test the program-counter, EXEC and
compare-mask rows, unwritten registers, and the arm and state limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:02:49 -05:00
MathiasDevelopes 485eb1aedd fix(libSceHttp): sceHttpWaitRequest reports no ready requests
It returned the network error, which titles that poll their epoll treat
as fatal. No request is ever pending, since sending fails at once, so the
wait now times out with no events; an infinite wait throws.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 20:48:20 +02:00
TideOPL c9685e47e4 fix(savedata): report a CREATE2 mount of an existing save as not created
sceSaveDataMount3 with SCE_SAVE_DATA_MOUNT_MODE_CREATE2 opens a save that
already exists, so its mount status is 0 rather than CREATED, as shadPS4's
savedata.cpp reports. A CREATE mount still reports CREATED.
2026-10-08 19:46:23 +01:00
TideOPL c17c5ebd4d fix(agc): apply the raw OOB_SELECT range rules to zero-stride vertex buffers
With stride 0, OOB_SELECT 2 puts a fetch out of range only when NUM_RECORDS
is 0, and OOB_SELECT 3 only when the offset is not below NUM_RECORDS (GFX10
table in Mesa ac_descriptors.c). A one-record descriptor therefore returns
its whole element: Unreal's per-draw PrimitiveId stream is such a descriptor,
and refusing it skipped the draw. A wholly out-of-range fetch reads a zero
buffer.
2026-10-08 19:46:22 +01:00
husari.orozco 4d13e99a0d test(relinker): execute the guest Intel trampolines end to end 2026-10-08 12:46:05 -06:00
clem-gb c91b306157 feat(http): accept sceHttpSetAuthInfoCallback
PPSA13427 imports sceHttpSetAuthInfoCallback (jf4TB2nUO40), which no
library exported, so the relinked title failed to load. No request
reaches the network, so no server asks for authentication: the
callback is accepted and never called. The signature and callback
type follow shadPS4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-08 20:42:24 +02:00
emirplus a8c2100f59 fix(savedata): ensure metadata precedes blob commit and handle rollback recovery
Write initial SaveDataParam metadata before replacing the memory blob so metadata failure cannot leave a prematurely grown blob. Handle blob write failure with metadata rollback, and allow retries to recover slots with missing metadata. Expand tests with nonzero data, blob failure, and fresh readback.
2026-10-08 21:41:09 +03:00
emirplus 8c45db7136 fix(relinker): restore full rcx for 32-bit register alu
Restore full 64-bit RCX before 32-bit ALU operation so CMP and other non-writing/carry instructions do not zero-extend and clear upper 32 bits. Add test coverage for 32-bit CMP, ADC, and SBB.
2026-10-08 21:36:42 +03:00
ArjenS-LA 74e1a6f5c4 fix(libc): convert wcsrtombs using guest characters 2026-10-08 11:32:21 -07:00
Celegans12 97b9439d4f perf(agc): size the storage and sampled texture caches to the device
The storage image and sampled texture caches each let go of their least
recently used entries past a fixed 2 GiB, and a sampled view of a
storage image counted that image a second time.

The storage image cache keeps a quarter of the largest device-local
heap, at least the 2 GiB of before (TextureCacheBudget). The sampled
cache gets what VK_EXT_memory_budget leaves on that heap after the
memory in use outside sampled textures and cached storage images, the
storage cache's budget and an eighth of the heap budget, read at most
once a second and at least 2 GiB; without the extension it keeps the
storage cache's rule. A snapshot counts its image allocation, a texture
still bound after leaving the cache counts as sampled memory, and a
change of more than 10% is logged at most every 10 s. A nonzero
APS5_TEXTURE_CACHE_MIB sets both budgets; a view of a cached storage
image counts nothing and leaves the cache when its image does.
2026-10-08 20:24:03 +02:00
hugodearaujo 3c7859c41d feat(libkernel): implement pthread_getname_np
Hades (PPSA03355) stops at load on main with "undefined symbol:
9HzfhdtESio", the NID of pthread_getname_np, which it calls on
pthread_self() with a 32-byte buffer. Measured on a PS5 (firmware 13.60)
through dlopen of libkernel: the function takes (thread, buffer), copies
the name and its terminator, returns an empty name for an unnamed
thread, ESRCH for a null or joined thread and EFAULT for a null buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:23:30 -03:00
alfalfa-star a2b049d455 feat(agc): accept 64-bit atomics in graphics shaders when the device enables them
The recompiler emits OpCapability Int64Atomics for 64-bit buffer atomics
in any stage, and the device enables shaderBufferInt64Atomics when it
has it, but graphics shader validation only accepted its fixed list of
capabilities, so every draw whose shaders use one was rejected with
"SPIR-V requires unsupported device capability 12". Compute dispatches
are not validated this way and already ran them.

The device records the feature (bufferInt64Atomics in the device state
and the graphics Context) and ValidateShaders accepts Int64Atomics when
it is enabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:16:01 +02:00
JAB-dev 1986905adb Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/ngs2-reverb-rack 2026-10-08 19:38:46 +02:00
JAB-dev d6821edc67 fix(libSceNgs2.native): clamp matrix levels to -4..4 as the PS4 libSceNgs2 does
The PS4 firmware 11.00 libSceNgs2.sprx stores matrix levels clamped to
-4..4, keeps NaN, and rejects a level count of 0. Levels were stored
unclamped, so a level of 8 played twice as loud as on the console, and a
count of 0 cleared the matrix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:36:19 +02:00
Scott Schuster 0b9b70fa36 feat(agc): accept 8_8_8_8 UINT color targets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:30:34 -05:00
john.maia 16824f2678 feat(videoout): implement sceVideoOutGetResolutionStatus
Three homebrew titles from #1578 import it and stop at start-up without
it: ps5-opengl (PPSA99005), EVO-PLAYER-PS5 (PPSA99039) and
ProsperoRadio (PPSA99001).

It reports the port's resolution as the full and pane size and the
refresh rate ID as sceVideoOutGetOutputStatus does. The 48-byte layout
follows the declarations in ps5-opengl and EVO-PLAYER-PS5, which agree;
the screen size is 0 and the flags are 0. An invalid handle or a null
status throws, as in the other status getters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:46 +01:00
LuisBiceps 9850628e1b test(libc): reset errno after the worker thread in guest_errors
guest_errors sets errno to 13 and checks at the end that the strerror_r
calls left it alone, but a std::thread is created and joined in between.
Guest errno is the host's errno. Since glibc 2.42, pthread_create first
tries madvise(MADV_GUARD_INSTALL) for the new thread's stack guard.
Kernels before 6.13, including WSL2's 6.6, reject it with EINVAL, and
glibc falls back to mprotect with errno left at EINVAL. POSIX leaves
errno unspecified after a successful call, so the test aborts on Ubuntu
26.04 (glibc 2.43) under WSL2 without anything being wrong.

Check errno right after the strerror calls, and set it to 13 again after
the join, so every errno check covers only strerror and strerror_r.
2026-10-09 01:21:00 +08:00
MathiasDevelopes 2c7d9b9c82 feat(agc): DMA_DATA prefetches to DST_SEL nowhere
DMA_DATA with DST_SEL 2 (V_411_NOWHERE in Mesa's src/amd/common/sid.h)
reads its source into L2 and stores nothing; libSceAgc emits it as an
L2 prefetch with the source address repeated as the destination. It
threw as a register or prefetch destination. A prefetch of a memory
source is now accepted and writes nothing: ResolveStore returns it as an
empty store, so the packet stays ordered without a drain,
DecodeMemoryCopy keeps rejecting it and Execute skips it. A prefetch of
a register, GDS or immediate source and a register destination still
throw.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 19:12:54 +02:00
muhzain05 fd597084f9 fix(ult): reject finalize with outstanding ulthreads
sceUltFinalize cleared gUlthreads directly, dropping the last
shared_ptr to an UltUlthreadState while its worker thread still held
the raw pointer passed to scePthreadCreate. Finalize now returns
ULT_ERROR_BUSY when an ulthread is still registered, before any global
state is torn down, following the BUSY convention of the queue,
semaphore and queue data pool destroy paths. Joining the ulthread
remains the caller's responsibility, as sceUltUlthreadJoin already
keeps the state alive across scePthreadJoin and erases it afterwards.
2026-10-08 10:51:50 -06:00
alfalfa-star 45541350bb feat(agc): accept UINT16_ABGR color exports into unsigned integer targets
SPI_SHADER_COL_FORMAT 7 (UINT16_ABGR) was rejected by DecodeState,
though the recompiler already handles it: a pixel shader's MRT output
under mode 7 is a uvec4, and a compressed export's 16-bit halves are
taken with OpBitFieldUExtract. The format is now accepted when the
target's CB_COLOR_INFO number type is UINT; into any other target it
still throws, as does SINT16_ABGR (8), whose halves would need sign
extension.

The target records the export (ColorTarget::uintExport). Shader
validation then requires a uint4 output at its location instead of a
float4 one, and blending into it is refused (Vulkan has no blending of
integer attachments).

PPSA14632 (LEGO Horizon Adventures) writes a 2848x1600 R8_UINT target
this way; those draws were dropped.

agc_driver_pixel_uint16_export draws compressed MRT0 exports under mode
7 into a linear 16_16_16_16 UINT target, one row per pair of packed
words (0x0000ffff/0xffff0000, 0x00010002/0xffffffff and four distinct
halves), and reads every 16-bit component back under the identity,
STD_REV and ALT_REV export mappings. agc_driver_graphics covers the
decode and the blend refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:46:09 +02:00
overlordxrz-source 18798620e8 feat(libkernel): implement sysctl and sysctlbyname for hw.ncpu
ScreenTester5 (PPSA69420) stops at start-up on the unresolved sysctlbyname
import and also imports sysctl. hw.ncpu (CTL_HW.HW_NCPU) reports the same
processor count as sysconf(_SC_NPROCESSORS_ONLN). Other names and MIBs throw.
2026-10-08 12:23:05 -04:00
emirplus c4c3ed7711 fix(savedata): recover from metadata setup failure
Report SAVE_DATA_ERROR_INTERNAL when setupSaveDataMemory2 fails to persist initial SaveDataParam metadata, and restore previous state so retrying setup can initialize cleanly. Closes #1667.
2026-10-08 19:18:36 +03:00
Michon 7208d7d314 fix(agc): a key fill over other images stays inside the image's DCC key extent; test the fill cover
When another live image overlaps the fill, a fill at a live image's dccAddress is a key fill
only while it stays within DccKeyCount (the pipe-aligned key count); with nothing overlapping
the length rule is unchanged. ClassifyFill, NoteKeysFill and ClearByKeysFill share the match.
agc_driver_fill_cover_keys pins Keys, Inside and Several for fills at and beside the keys.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 18:06:37 +02:00
klosixgaming-arch 5d3029b45a fix(shader): work around Intel iGPU OpSMulExtended bug
Use Hacker's Delight 8-3 formula for signed multiplication high words:
hi = umulhi(a,b) - (a<0 ? b : 0) - (b<0 ? a : 0)

This avoids using OpSMulExtended entirely, which returns wrong high words
for constants -1, -2, and -32768 on Intel iGPUs. The workaround is exact
for all inputs and has no performance impact on other platforms.

Fixes #1246
2026-10-08 11:02:58 -05:00
Morten Holm 20e8bb09ba fix(libc): run guest exit handlers before the host exit handlers
LibcExit called std::exit, which ran the static destructors of the libraries
before the guest exit handlers. A guest handler that freed memory then locked
a destroyed std::mutex, which throws, and a noexcept guest destructor ended in
std::terminate. The guest handlers now run first, while the library objects
are alive.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 17:53:56 +02:00
Jan Šlégl e6a9b50512 feat(libkernel): implement the sigset functions
Add sigemptyset, sigfillset, sigaddset, sigdelset and sigismember with
FreeBSD 11 semantics (lib/libc/gen/sigsetops.c): a 128-bit set of four
32-bit words, signal n at bit n - 1, signals 1 to 128 valid. sigfillset
sets every bit. An invalid signal returns -1 with errno EINVAL and leaves
the set untouched; sigismember returns 1 or 0. A null set throws.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 17:45:57 +02:00
emirplus b4cc6d26b9 feat(relinker): support Windows guest TLS reads by ALU register-address instructions
Recognize read-direction ALU forms (add, or, adc, sbb, and, sub, xor, cmp) that read from fs:[mem] where mem has a base or index register (such as 64 48 33 03, xor rax, fs:[rbx], in #217). The stub loads the TLS value through the computed address, performs the ALU operation, and preserves scratch registers and flags.

Extend test_tls_function_coverage with execution and stub coverage cases for register-addressed ALU operations, including rax, rcx, rbx and r13 destinations, wide and 32-bit forms, and verification of register and flag preservation.

Refs #217

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:39:24 +03:00
Pedro a294b80d29 feat(libkernel): implement getuid, geteuid, getgid, getegid and issetugid
Part of #1578.
2026-10-08 10:39:06 -05:00
XairRrR df3aa1a9db fix(libkernel): raise the open file soft limit on Linux
Each direct memory backing keeps a memfd open, so a title such as
Dreaming Sarah (PPSA02929) holds about 1100 descriptors at startup.
With the systemd default soft limit of 1024, later opens fail with
EMFILE: memfd_create throws "create direct memory backing: Too many
open files", or the title's fopen returns NULL and it faults in fread.

libkernel now raises the RLIMIT_NOFILE soft limit to the hard limit
when it is loaded, before the title creates any descriptor, and throws
if the limit cannot be read or raised.
2026-10-08 17:38:48 +02:00
Nahuel Genchi 5115c24fc7 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into fix-flip-compute
# Conflicts:
#	core/libs/prx/libSceAgcDriver/CMakeLists.txt
2026-10-08 12:36:13 -03:00
st44rplatinum 7894cda94d feat(libSceSystemService): implement Disable/ReenableMediaPlay 2026-10-08 18:35:19 +03:00
Morten Holm 5333a20537 fix(agc): do not use fragment barycentric on MoltenVK
MoltenVK reports VK_KHR_fragment_shader_barycentric, but its SPIR-V to MSL step
rejects the PerVertexKHR decoration that the barycentric path uses, so every
pixel shader on that path fails to compile into a pipeline. Treat the feature
as unavailable when the driver is MoltenVK, so the no-barycentric path is used.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 17:31:20 +02:00
Pacuka 7647710248 test(audiodec): cover the raw M4AAC configuration search with a 5.1 stream
A raw 5.1 LC frame decodes as 6 channels with a maximum of 6 and of 8,
which is only reached by moving past the mono/stereo configuration. The
configuration search is listed under unknown function info, together with
a mono raw stream being reported as 2 channels.

Co-authored-by: Dextroid17 <217507631+Dextroid17@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:29:50 +02:00
Pacuka 7b722253a4 fix(audiodec): take the M4AAC raw channel layout from the stream
For a raw M4AAC stream the maximum channel count was written into the
AudioSpecificConfig as the channel configuration. The maximum only bounds
the stream: The Smurfs Dreams creates its decoder with 8 channels at most
and sends stereo, so FFmpeg refused configuration 8 (reserved) and a
stereo stream under configuration 6 or 7 decodes no frame. The decoder
now starts from the mono/stereo configuration and on the first access
unit that it cannot decode moves on to the configurations with more
channels, up to the maximum, keeping the first one that decodes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:29:46 +02:00
Michon fc05d1e3e3 fix(agc): a fill of a surface's DCC keys is a key fill over other images' memory
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 17:27:13 +02:00
Mohd Faour ce5a2136a8 fix(sysmodule): report a module that is not loaded as SCE_SYSMODULE_ERROR_UNLOADED
sceSysmoduleIsLoaded returned 0x80A90002 and the unload calls 0x80A90003
for a module that is not loaded. Neither value exists in the SDK: the
sysmodule facility is 0x5A and the error is 0x805A1001, which titles
compare against (GTA V PPSA04263: cmp eax,0x805a1001 after IsLoaded) to
decide whether to load and initialise the module themselves. Return that
value from all three places and cover it in guest_sysmodule.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 17:13:02 +02:00
ahmedhamouda78 73eb8465d6 feat(agc): write the measured sceAgcDcbResetQueue packet sequence
Replace the CLEAR_STATE approximation with the envelope and per-op-bit packet groups measured on PS5 firmware 13.60. Emit groups for op bits 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x080, 0x100 and 0x800 in ascending order; throw for 0x040, 0x200 and 0x400 whose packets the driver rejects. state 2 sets the envelope flag and state 3 sets the 0x004 and 0x800 group payload dword.
2026-10-08 15:10:08 +00:00
Leandro 9bae5b0879
Merge branch 'main' into fix/kernel-download0-at-start 2026-10-08 17:09:06 +02:00
Scott Schuster a43f1411c4 fix(libc): align guest heap allocations to 32 bytes
Clang's PS4 and PS5 targets set the default new alignment and the suitable
alignment to 32 bytes, so PS5 code may store to a fresh malloc or operator
new result with 32-byte-aligned AVX instructions. The guest heap aligned
blocks to 16 bytes, and the arena's 32-byte classes put every small block
16 bytes past a 32-byte boundary after its header, so such a store faulted.
The minimum alignment is now 32 bytes; the padding still assumes only the
16-byte alignment the raw blocks guarantee.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:42:06 -05:00
Scott Schuster f983f51223 fix(agc): write queued labels at a suspend point before a device exists
A suspend point flushes the labels queued since the last submission. It
recorded them only when a Vulkan device existed, and the device is created
lazily, so labels queued by a title that had not yet drawn were never
written. RADV ends each submission with a RELEASE_MEM to a marker it polls
from the CPU; when the end of that submission was folded into a following
suspend point, the marker stayed at 0 and RADV reported the device lost.
The labels are now recorded either way, which writes them from the CPU
without a device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:40:37 -05:00
LeandroLP23 c1c7c7fc56 fix(kernel): skip the download0 mount when param.json cannot be read
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:07:18 +02:00
krishnaraya 9157dfd7ed fix(libSceAgcDriver): read the RELEASE_MEM interrupt select only from RELEASE_MEM packets
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 09:49:11 -04:00
clem-gb d16cac0ab2 fix(relinker): keep PT_GNU_EH_FRAME in the relinked executable
The segment filter dropped every header in the PT_LOOS..PT_HIOS range,
which includes PT_GNU_EH_FRAME. The unwinders find the executable's
unwind tables through that header, so no C++ exception thrown in the
main executable could be caught on Linux.

The header is kept only when the output program header table still fits
in the input's table; otherwise it is dropped as before, with a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-08 15:47:39 +02:00
popcoder565 24dc98d7c0 fix(libkernel): give up a raise whose target stays in NtContinue or winpthreads
The retry that waits for a target to leave NtContinue, NtContinueEx or
libwinpthread-1.dll had no bound, so a target that stayed there made
sceKernelRaiseException spin forever. It now throws after 1 s. A new
guest_raise_exception phase keeps a thread inside NtContinue by
continuing a context that calls NtContinue again, and checks that the
raise throws and that the handler did not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:47:25 -04:00
Zheorgyan 847bd9f496 fix(shader): keep v_exp_f32 at or above the smallest normal for inputs from -126 2026-10-08 14:59:28 +02:00
MathiasDevelopes 8685c14d16
feat(recompiler): convert f32 to f16 natively when the device rounds 16-bit floats to nearest even
The integer emulation of the round-to-nearest-even float-to-half
conversion is exact but costly: a compute shader with about 3600
conversions never finished compiling on NVIDIA. When the device enables
shaderFloat16 and guarantees shaderRoundingModeRTEFloat16,
shaderDenormPreserveFloat16 and shaderSignedZeroInfNanPreserveFloat16,
it advertises Float16, RoundingModeRTE and DenormPreserve, and the
recompiler emits OpFConvert under the 16-bit RoundingModeRTE,
DenormPreserve and SignedZeroInfNanPreserve execution modes instead.
NaNs keep the emulated quiet NaN with the high payload bits. Devices
without these guarantees keep the emulation.

Graphics validation accepts the RoundingModeRTE, DenormPreserve and
SignedZeroInfNanPreserve execution modes for 16-, 32- and 64-bit floats,
so vertex and pixel shaders with a native conversion still draw.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 12:51:07 +00:00
Zheorgyan ed14c24bd7 test(agc): skip the exec host lanes vertex draw without vertex subgroups 2026-10-08 14:43:17 +02:00
krishnaraya ee9033f9cd test(agc): check device capabilities by name in the execution tests
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 08:29:12 -04:00
Arvind Frøiland 0858f01429 test(relinker): check decoder lengths against an LLVM-generated table
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:09:18 +09:00
SK Arin 6e951bd0ed fix(progress): exclude library test fixtures from function counts 2026-10-08 17:30:43 +05:30
SK Arin 466ebde23c fix(oracle): publish cached executable only after successful build 2026-10-08 17:16:36 +05:30
hamb3r 8ed4ff55b5 fix(agc): validate stencil clear before decoding stencil operations 2026-10-08 14:16:10 +03:00
Aryan Sharma 72e8d502f9 fix(agc): draw with DB_RENDER_CONTROL STENCIL_CLEAR_ENABLE
A draw that sets STENCIL_CLEAR_ENABLE was rejected as a whole, so its
color output was lost as well. The draw is now rasterized with every
covered sample's stencil replaced by DB_STENCIL_CLEAR, whatever the
stencil and depth tests are, and its color outputs are written as usual.
The depth/stencil state is decoded for such a draw even when
DB_DEPTH_CONTROL enables no test. Depth clear, copy, resummarize and
decompress draws are still rejected.
2026-10-08 14:16:10 +03:00
popcoder565 d3cdffac25
Merge branch 'main' into perf/bda-store-byte-loop 2026-10-08 07:03:25 -04:00
popcoder565 d80d5ff8c6 fix(libkernel): give a sleep nested in an APC its own timer on Windows
SleepUntil, PollSleepUntil and SleepNanosCoarse each wait on one
thread_local high-resolution timer. A sceKernelRaiseException handler
that runs as an APC inside a sleeping thread's wait and sleeps itself
re-armed that timer and consumed its signal, so the interrupted sleep
never returned. A nested TimerWait now waits on its own timer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:01:09 -04:00
CyanBook 42f42ae228 docs(debt): drop sce::Json::Value::clear from PPSA23566 unknown signatures 2026-10-08 12:45:25 +02:00
Kikoarl 319ac9ba78 test: give cpu topology and icon resource temp paths a random suffix 2026-10-08 12:40:39 +02:00
Sanjaysrinivas d9afb0af62 test(shader): cover half expansion bit patterns 2026-10-08 12:19:59 +02:00
TideOPL 8b28f53a4d revert(libkernel): move the process time fix to its own pull request 2026-10-08 11:00:22 +01:00
TideOPL 383770ff65 fix(libkernel): read the process start before the clock in process time
sceKernelGetProcessTime and sceKernelGetProcessTimeCounter subtracted
GetStartNanos() from GetMonotonicNanos() in one expression. GCC reads the
clock first, so on the first call in a process the start was captured
after it and the result wrapped to about 2^64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:59:30 +01:00
TideOPL 74a4d47133 Merge remote-tracking branch 'origin/main' into pr1076
# Conflicts:
#	core/libs/prx/libScePad/Export.cpp
2026-10-08 10:46:36 +01:00
LeandroLP23 81624a6a18 refactor(recompiler): share the control flow helpers
toHexString, contains, intersectSorted, addUnique, sortUnique, remapId,
remapIds and rebuildPredecessors were defined with identical bodies in
the anonymous namespaces of two of ControlFlowGraph.cpp, GraphBuilder.cpp
and Structurizer.cpp. They are now declared in ControlFlowHelpers.hpp,
which only these three files include, and defined in ControlFlowGraph.cpp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:06:31 +02:00
TideOPL e91fd5a720 fix(agc): prefer the pending image of exactly a sampled surface over an aliasing mip chain
FindPending returned the first pending storage image at a texture's
address that is at least as long as the surface. When transient
surfaces alias (a 2-mip 1424x800 chain and, after it, a 1-mip
1424x800 surface at the same address, each with its own DCC keys),
a sampled lookup of the newer single-mip surface could be served by
the older chain: the chain's view was refreshed under its own keys,
which the title had re-filled with a fast-clear code, so whole blocks
read as the clear value instead of what the GPU had just written.

An image whose length equals the surface's now wins; a longer chain
still serves a descriptor of its first mips when no exact image is
pending.
2026-10-08 10:06:26 +01:00
TideOPL 9d65003ced fix(agc): treat other-shaped views of a depth surface's memory as reused memory
Engines alias transient render targets, so a texture can sit at the
address of a depth surface after the memory has been handed to a color
image: a 384x384 R11G11B10 texture over a 384x384 D32S8 surface, say.
Sampling it threw "sampling the depth plane ... is not implemented"
and the draw was skipped.

A view with another extent, or a depth-plane view in a format that
cannot hold the plane (neither the plane's own R32F / R16 unorm nor a
T# that reads the raw depth bits), is now treated as memory reuse: the
lookup falls through to the ordinary texture path instead of the depth
surface. Stencil-plane views keep their current handling.
2026-10-08 10:06:11 +01:00
Aryan Sharma d77bc7c363 fix(libkernel): return EBUSY when destroying a locked mutex
scePthreadMutexDestroy threw when the mutex was locked. FreeBSD libthr,
which the console's libkernel follows, returns EBUSY and leaves the
mutex usable; PPSA28997 destroys a locked mutex during its intro and
was aborted.
2026-10-08 14:25:16 +05:30
clem-gb 7406c975d2 fix(libkernel): release every level of a recursive mutex during a cond wait
A condition wait on a recursive mutex locked more than once unlocked the
native mutex only once, so the thread that should signal blocked forever
on it. Unlock the remaining levels before the wait and lock them again
after it, as FreeBSD libthr does in _mutex_cv_unlock and _mutex_cv_lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-08 10:53:58 +02:00
clem-gb 15c1962e82 fix(libkernel): keep ymm upper halves across a redirected raise
A thread that sceKernelRaiseException redirects resumes through
RtlRestoreContext with a CONTEXT that has no XSTATE, so the upper halves
of ymm0-ymm15 came back as the handler and the delivery path left them.
A handler or host routine that runs vzeroupper or any VEX instruction
(Zen 2 guest code, the CRT's memcpy) cleared the upper lanes of a thread
interrupted in the middle of AVX code. The entry stub now stores
ymm0-ymm15 next to the delivery when the CPU and the OS enable AVX, and
the exit loads them back right before RtlRestoreContext, which restores
only the low halves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-08 10:47:33 +02:00
clem-gb 2ba8f75e15 fix(libkernel): report the current CPU within the thread's guest affinity
sceKernelGetCurrentCpu returned the raw host CPU index. Guest affinities
are bookkeeping only and sceKernelGetAvailableCpumask advertises CPUs 0
to 12, so on a host with more than 13 logical CPUs a title could get 13
or higher, and a thread pinned to one CPU could get another one.

The host index now selects a CPU of the calling thread's affinity
clipped to the available mask, so the result is always an advertised
CPU and a thread pinned to one CPU reports that CPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
2026-10-08 10:47:33 +02:00
LeandroLP23 84fa55722d fix(kernel): create /download0 at start-up when the title declares download data
On the console a title whose param.json declares downloadDataSize finds
/download0 mounted from the start. The host directory was only created
by sceAppContentDownloadDataGetAvailableSpaceKb, so a title that opens
files there directly got ENOENT. libkernel now creates it when it loads,
reading only the run directory's param.json, without resolving guest
paths, so the libc path root is still fixed at first use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:18:22 +02:00
Suryansh Prajapati 58f596ee89 fix(shader): convert f16 bits to f32 without UnpackHalf2x16
On the AMD Windows driver (Radeon RDNA2 iGPU, 32.0.21030.2001)
UnpackHalf2x16 of a byte-selected half converts the unmasked source
register: an SDWA BYTE_0 source of 0xfff0fff0 reads as f16 0xfff0
instead of 0x00f0, so agc_driver_sdwa_float_selectors and
agc_driver_sdwa_ldexp_f16 fail there. EmitF16BitsToF32 now decodes
sign, exponent and mantissa with integer operations, scaling
subnormals by 2^-24, which is exact for every half and leaves the
driver nothing to fold into the conversion.
2026-10-08 13:36:49 +05:30
popcoder565 384078c924 fix(libkernel): retry a raise that interrupts its target inside winpthreads
MinGW's thread_local goes through emutls and winpthreads' pthread_getspecific, which holds a per-thread spinlock. A raise that redirected a thread holding it ran the handler on that same thread, and a handler reading any thread_local, scePthreadSelf for one, spun on the lock forever. A raise that finds the target inside libwinpthread-1.dll now resumes it and suspends it again, as one inside NtContinue does.

guest_raise_exception's new phase raises at a thread that calls scePthreadSelf in a loop and checks that the handler sees its own thread. It hung in every run without the retry. TechnicalDebt records that a handler can still reenter other host code the thread was interrupted in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:43:13 -04:00
Claude 9abc931a18
refactor(libkernel): share eh_frame_hdr parsing between module info calls
sceKernelGetModuleInfoForUnwind and sceKernelGetModuleInfoFromAddr each
parsed .ehmeta and the eh_frame_hdr it names. Both now read them through
Module/EhFrame.hpp, so a bad table fails the same way in both: an
eh_frame_hdr version other than 1, an indirect or non-absptr/pcrel
encoding, a 64-bit record length or anything outside the image throws.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkiyF6p7oDAaTtVe8ci5zP
2026-10-08 06:47:14 +00:00
TibixDev ce280a19ca perf(agc): handle uniform pattern-fill kernels as clears
Recognize the exact typed pattern-fill kernel and route aligned, nonaliased uniform ranges through existing fill/coherence handling. Preserve control and descriptor bounds, partial dispatch counts, queued labels, and shader fallback for other cases.

Semantics checked on Radeon RX 6600: native RDNA wave32/wave64 typed R32_UINT loads/stores, execution masks, and descriptor bounds (16 cases). Real PM4 tests cover HLE and shader paths, imports and copies, indirect/partial dispatch and GPU-to-label ordering under Vulkan validation. Graphics and PM4 tests pass; Skyrim Helgen save visually checked. 64 MiB copied-buffer fill median reduced from 67.5 ms to 3.8 ms.

Written with AI assistance.
2026-10-08 09:08:38 +03:00
MathiasDevelopes 77ef75c1da
feat(libkernel): implement sceKernelGetModuleInfoFromAddr on Windows
Read the module layout from the PE image that holds the address. A
relinked image reports its .elf sections as segments and the
eh_frame_hdr recorded in .ehmeta; any other image reports its sections
with memory access and its .ehfram section. The eh_frame_hdr and
eh_frame helpers are shared with the Linux path, and the guest module
info test now also runs on Windows.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 05:46:48 +00:00
Nahuel Genchi 0543e636ef test(agc): match the unreadable-code error and run the flip compute mode in ctest 2026-10-08 01:57:33 -03:00
popcoder565 175846186a fix(libkernel): read the raise target's context before choosing APC delivery
SuspendThread returns before the thread has stopped, and GetThreadContext waits until it has. waitCount was read right after SuspendThread, so a thread that was leaving its wait could still decrement it and drain its APCs with NtTestAlert before QueueUserAPC queued the delivery, which then waited for an alertable wait that never came. The context is now read first, so waitCount is read from a stopped thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:53:58 -04:00
popcoder565 c3f3cc849a test(libkernel): raise exceptions at a thread that keeps continuing SEH exceptions
The new phase's vectored handler continues every exception the thread raises, so the thread spends much of its time in NtContinue, where a redirect is lost unless the raise retries. Without the retry the phase hangs in every run; with it the test passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:53:58 -04:00
raghav314 dfa179f43f fix(relinker): write a bucketed hash table for Linux guest modules
The Linux guest module writer emitted DT_HASH with a single bucket, so
every symbol lookup that reached a guest module walked its whole symbol
table. Guest modules come first in the global scope, so each host prx
lookup paid that walk at load and on every lazy PLT call. Build the
standard SysV table from the final symbol names with one bucket per
symbol, as the console's modules ship it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:20:45 +05:30
popcoder565 f8c1e0c64f fix(libkernel): keep sceKernelRaiseException redirects out of NtContinue
A raised exception redirects the target thread to a stub that runs the handler and returns through RtlRestoreContext. On Windows 10 (19045) RtlRestoreContext restores in user mode only when the context flags are exactly CONTEXT_FULL | CONTEXT_SEGMENTS (CONTEXT_XSTATE aside); for the CONTEXT_FULL | CONTEXT_FLOATING_POINT context it was given, it calls NtContinue. When the next raise suspended the thread inside that system call, NtContinue then replaced the redirected context with the one it was restoring, so the handler never ran although sceKernelRaiseException had returned 0. guest_raise_exception lost such a delivery to its busy thread in about one run in five and hung until the ctest timeout.

The context is now read with CONTEXT_SEGMENTS, so the handler returns through the user-mode restore, and a raise that finds the thread inside NtContinue or NtContinueEx (an APC or an exception handler returning) resumes it and suspends it again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:48:16 -04:00
xsvm 2daa034e87 perf(relinker): write in-place --to-intel substitutions directly
Each in-place substitution went through X64InstructionRewriter::Rewrite,
which copies the whole code segment and decodes every instruction in it
to adjust references. The converter only accepts equal-length
replacements, so the adjustment is always zero and the copy and scan are
wasted: conversion time grew by one segment scan per substitution. Copy
the replacement bytes into the segment instead.
2026-10-08 10:19:39 +08:00
krishnaraya 480b04801c fix(shader): compute V_FRACT_F32 from the exact fraction of |x|
Co-authored-by: Hashaam Zafar <68960089+hashaam1217@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 22:06:57 -04:00
raghav314 1a2bbc5d3e fix(videoout): create the window and the device when VideoOut starts
The driver created a windowless Vulkan device at the first dispatch and
replaced it with a windowed one at the first flip. The replacement built a
second device and re-imported every host import, and the first flip paid
for it.

VideoOut now creates its window when it starts (the first VideoOut call),
at the default 1920x1080 output, and attaches it to the driver
(AgcDriverAttachWindow) before the call returns. The driver creates its
device with that window, so GPU work and presentation use one device.
Present no longer creates or replaces a device. A device created by GPU
work before VideoOut started is still replaced, now in AttachWindow.

A failure to create the window or the device is thrown from that first
VideoOut call instead of terminating the presentation thread.

Tests:
- video_out_flip_tests onedevice: GPU work, then a flip, leaves one device.
- pacing makes its first presentation span vblanks with GPU work queued
  ahead of the flip; it relied on the device being created at the flip.
- unavailable expects the failure from sceVideoOutOpen.
- guest_video_out_wqhd_detection writes a param.json for the window title
  and is skipped without a display or Vulkan device unless
  ANYPS5_REQUIRE_DISPLAY is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:54:05 +05:30
Chad f4edc9ae92 fix(recompiler): split image reads whose descriptor is a web of SRT Phis
SplitDescriptorPhi (#414) handles a T# or S# that is a Phi of SRT reads in
one block. A descriptor picked inside a loop through a jump table reaches
the read as a chain of Phis rooted at the loop header, so the plan threw
"GetImageResource dword 0 is not a valid runtime value".

When the one-block split does not apply, walk the descriptor dwords
together through the Phi web, give each distinct SRT descriptor an arm,
build a U32 selector Phi web carrying the arm index, and select between one
copy of the read per arm. Paths whose dwords hold a program-counter, EXEC
or ballot value fold onto the first arm (listed in TechnicalDebt); any
other descriptor that cannot be recomputed still throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:07:43 -05:00
Scott Schuster 1dca7b4f40 perf(recompiler): load the written-page slot before the CAS
note_bda_write ran a device-scope compare-exchange on every probe, also
when the slot already held the page. The table lives in host-visible
memory, so each BDA store paid an atomic across PCIe, and nearly every
store hits a page an earlier store noted. Load the slot first and only
compare-exchange when it does not hold the page. The slots probed, the
pages recorded and the overflow report are unchanged.

DOOM (PPSA99666) presents through a compute kernel that stores about two
million pixels through raw pointers per frame: 248 ms per dispatch
before, 8.1 ms after, on an RTX 5070 Ti.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:07:13 -05:00
popcoder565 2e60f5585e refactor(recompiler): keep the BDA byte write helper beside the store path
The declaration, the state field and the definition of write_bda_bytes now sit next to EmitBdaStore and the other BDA write functions instead of next to the dword read functions, which #1267 extends at the same lines. No change to the emitted code.
2026-10-07 16:49:06 -04:00
popcoder565 a4643ede97 perf(recompiler): probe the written-page slots of a BDA write in a loop
note_bda_write unrolled its 8 compare-exchange probes, and drivers inline it at every BDA store and atomic. The probes now run in a loop that tries the same slots in the same order and stops at the same slot, so the recorded pages and the overflow flag are unchanged. With the byte store helper, the agc_driver_flat_store binaries on an RTX 3060 go from 138,240 to 75,648 bytes (wave32) and from 225,152 to 130,560 bytes (wave64), and the cold run from 2.2 s to 1.2 s.
2026-10-07 16:18:43 -04:00
popcoder565 70a8844089 perf(recompiler): emit BDA byte stores through one looping helper
Every 8- and 16-bit BDA store and the unaligned path of every 32-bit store emitted one get_bda_write_pointer lookup and one note_bda_write per byte at the store site, five write lookups per 32-bit store. They now call write_bda_bytes, which loops over the bytes and does, per byte and in order, the same lookup, the store when it is mapped and the write note, so faults are recorded exactly as before. On an RTX 3060 the agc_driver_flat_store binaries shrink from 496,256 to 138,240 bytes (wave32) and from 928,384 to 225,152 bytes (wave64), and the cold run from 19.7 s to 2.2 s.
2026-10-07 16:18:43 -04:00
alfalfa-star afb6d1e165 perf(agc): keep draw snapshots of storage buffers up to 1 GiB
Recorder::KeepDrawSnapshot keeps nothing larger than the pool's byte
budget, and the storage-buffer pool's budget was 256 MiB (the draw
input pool, for vertex and index data, has 1 GiB). A read-only storage
buffer a draw reads in place from an import is copied into a snapshot
per draw; one larger than 256 MiB was never kept, so every draw copied
it again even when the guest had not touched it.

PPSA14632 (LEGO Horizon Adventures) binds a 576 MiB direct-memory buffer
to many draws: each one memcpy'd all 576 MiB (about 100 ms), 176 times
in 60 s. With the budget at 1 GiB, as for draw inputs, the snapshot is
reused while the buffer is unchanged (394 reuses and 41 copies in 90 s),
and Graphics::Draw drops from about 7 ms to 1 ms per draw packet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:14:10 +02:00
TideOPL 71e0f6428f style(libScePad): remove code comments
Per CONVENTIONS, code comments only mark technical debt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:06:09 +01:00
TideOPL efa6cd56f0 fix(libScePad): queue input states for scePadRead
scePadRead reported only the current state, so input that changed and
changed back between two reads was lost. Published states are now kept in
a queue of up to 64 and drained oldest first; with none queued the current
state is returned as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:03:30 +01:00
TideOPL efa5afbfbd fix(libkernel): read the process start before the clock in process time
sceKernelGetProcessTime and sceKernelGetProcessTimeCounter subtracted
GetStartNanos() from GetMonotonicNanos() in one expression. GCC reads the
clock first, so on the first call in a process the start was captured
after it and the result wrapped to about 2^64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:03:30 +01:00
alfalfa-star 57a529d5bf feat(videoout): use sce_sys/icon0.png as the window icon
The display window now takes its icon from /app0/sce_sys/icon0.png when
the game has one, decoded with the existing PNG decoder and set through
SDL_SetWindowIcon. Linux executables have no icon resource, so the
window, taskbar and alt-tab showed a generic icon; on Windows the
embedded resource from #350 already covers this and the call only
reinforces it. Without icon0.png nothing changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:41:26 +02:00
TideOPL cefb5a9fc0 docs(libScePad): record the scePadRead queue gap in technical debt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:15:39 +01:00
JAB-dev e493328eb7 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/ngs2-reverb-rack 2026-10-07 07:01:30 +02:00
JAB-dev e15f1644e3 fix(libSceNgs2.native): reverb as the PS4 libSceNgs2 does
The reverb was a Freeverb-style approximation. It now follows the PS4
firmware 11.00 libSceNgs2.sprx, read and checked against its output: the
input mixed to mono with the library's fixed gains, a 14400-sample buffer
with four reflection taps from the reflection pattern tables and a late
feed, sixteen damped comb filters with a pre-emphasis stage, a signed
selection of combs and four allpasses per output channel, a two-pole room
HF filter, and the library's parameter clamps, crossfades and setup
defaults. The test values are the PS4 library's own output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 01:26:11 +02:00
JAB-dev 34bdc37b76 feat(libSceNgs2.native): reverb rack with I3DL2 parameters
Rack 0x2001 is created with its option layout and KytyPS5's defaults, takes
the setup (0x20010000) and I3DL2 (0x20010001) voice params and reports the
common voice state. The voice mixes its inputs and runs a Freeverb-style
approximation driven by the I3DL2 parameters: room and room HF, early
reflections and their delay, late reverb and its pre-delay, decay time and
HF ratio, and diffusion. Out-of-range params throw, param changes keep the
tail, a stop or kill clears it, and the tail ends once it decays below
1e-20. The console's algorithm is unknown; the approximation is recorded in
TechnicalDebt. The test context buffer pool grows to 64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:21:28 +02:00
Mehran 39e7a36221 perf(agc): query unit shadows without copying the overlap list 2026-10-06 12:49:15 +03:00
Mehran d37366a5d8 perf(agc): reset the PM4 queue state without a 48 KiB stack temporary 2026-10-06 12:49:13 +03:00
1735 changed files with 176405 additions and 10813 deletions

View File

@ -0,0 +1,81 @@
title: "Game name (PPSA00000)"
body:
- type: markdown
attributes:
value: |
One thread per title, for every platform: search this category for the title ID first. If a thread exists, reply there, also when your OS or GPU differs from the one it reports.
Name the discussion `Game name (title ID)`, for example `DOOM Shareware (PPSA99666)`, without the platform.
Bug reports and implementation work belong in issues and pull requests; link them here as the blocker.
Per-game progress is also tracked on the [blocker map](https://alxcbtw.github.io/anyps5-roadmap/), built from public GitHub data. Only share material you have the right to distribute.
- type: checkboxes
id: searched
attributes:
label: Existing thread
options:
- label: I searched this category for the title ID and no thread exists for this title on any platform.
required: true
- type: input
id: title
attributes:
label: Title
description: Name and title ID from `sce_sys/param.json`.
placeholder: DOOM Shareware (PPSA99666)
validations:
required: true
- type: markdown
attributes:
value: |
### First report
The fields below describe one run. Other systems and content versions are added to the thread as replies.
- type: input
id: version
attributes:
label: Content version tested
description: The content version from `sce_sys/param.json`.
placeholder: 01.001.001
validations:
required: true
- type: input
id: commit
attributes:
label: AnyPS5 commit
description: The `main` commit that was built, or the release that was used, and any pull requests merged on top.
validations:
required: true
- type: input
id: system
attributes:
label: System tested
description: OS, GPU and driver version, and the compiler if you built it yourself.
placeholder: Arch Linux, GCC 16.2.1, RTX 5080 (NVIDIA 615.78.08)
validations:
required: true
- type: dropdown
id: reached
attributes:
label: Furthest point
options:
- Does not convert
- Stops before the first frame
- Logos or loading screen
- Menu
- In game
validations:
required: true
- type: textarea
id: seen
attributes:
label: What is shown
description: The last screen that was seen, the frame rate there, and what works or is missing (picture, audio, input).
validations:
required: true
- type: textarea
id: blocker
attributes:
label: Current blocker
description: The line where it stops, the issue that tracks it, and the open pull requests and local changes the title still needs.
- type: textarea
id: steps
attributes:
label: How it was run
description: Commands and environment variables, and what the title needed beyond the usage guide.

65
.github/ISSUE_TEMPLATE/performance.yml vendored Normal file
View File

@ -0,0 +1,65 @@
name: Performance report
description: A slow scene or a change in speed, measured with a performance trace so that reports can be compared.
title: "perf: "
body:
- type: markdown
attributes:
value: |
Capture the scene with `APS5_TRACE_FRAMES=<start>:<count>` (presents; `APS5_TRACE_SECONDS=<start>:<length>` also works), as described under [Performance trace](https://github.com/boykopovar/AnyPS5/blob/main/docs/dev/BUILD.md#performance-trace). It writes `aps5-trace-<commit>-<pid>.json.gz` and appends one line to `aps5-summary.jsonl`.
- Run the scene once and restart the title, so the shader and pipeline caches are warm.
- Use the same scene, window, resolution and settings for every capture you compare.
- Set no other `APS5_TRACE_*` or `APS5_PROFILE_*` switch and do not redirect the log; they cost time.
- Capture the base and the change on the same machine in the same session.
A trace holds timings, scope and thread names and counts, no game data. The summary line names the GPU, driver and OS.
- type: input
id: scene
attributes:
label: Title and scene
description: Title ID and what the window covers (menu, level, position, cutscene).
placeholder: PPSA01325, main menu after the intro
validations:
required: true
- type: textarea
id: observed
attributes:
label: What is slow or what changed
description: What you see (frame time, stutter, a phase that grew) and, for a comparison, the two commits.
validations:
required: true
- type: textarea
id: summary
attributes:
label: Summary lines
description: The line of aps5-summary.jsonl for each capture. It holds the commit, the APS5_* switches, GPU, driver, OS, resolution and frame times.
render: json
validations:
required: true
- type: textarea
id: trace
attributes:
label: Traces
description: Attach each aps5-trace-<commit>-<pid>.json.gz (drag it into this field). They open in ui.perfetto.dev.
validations:
required: true
- type: textarea
id: digest
attributes:
label: Digest
description: The output of `python3 tools/trace_digest.py <trace>` (with `--stacks <file>.collapsed.txt` if you sampled the worker).
- type: textarea
id: stacks
attributes:
label: Worker stacks
description: Optional. The collapsed-stack file of APS5_SAMPLE_WORKER (<file stem>.collapsed.txt), attached. It opens in speedscope.app.
- type: checkboxes
id: protocol
attributes:
label: Capture
options:
- label: The caches were warm (the scene ran once and the title was restarted)
required: true
- label: No other APS5_TRACE_* or APS5_PROFILE_* switch was set and the log was not redirected
required: true
- label: Captures compared here come from the same machine, scene and settings

View File

@ -1,16 +1,18 @@
### What
### Tested
<!-- OS, title or homebrew, what was checked. "Not tested" is a valid answer. -->
<!-- OS, title or homebrew, what was checked. "Not tested" is a valid answer. A performance change: the summary lines of main and of this PR from the same machine and scene, with the traces attached, captured as the Performance report issue form describes. -->
### Checklist
<!-- Rules behind each item: https://github.com/boykopovar/AnyPS5/blob/main/CONTRIBUTING.md -->
- [ ] Based on current `main`; no other open PR implements the same functions
- [ ] One topic per PR; follow-ups go in a new PR
- [ ] No comments in code except [technical debt](https://github.com/boykopovar/AnyPS5/blob/main/docs/dev/CONVENTIONS.md)
- [ ] Unimplemented paths throw (`NotImplemented_nid_no_patch`); silent stubs are listed in [TechnicalDebt](https://github.com/boykopovar/AnyPS5/blob/main/docs/dev/TechnicalDebt.md#silent-stubs)
- [ ] Unimplemented paths throw (`NotImplemented_nid_no_patch`); silent stubs are listed under Silent stubs in their library's [technical debt](https://github.com/boykopovar/AnyPS5/tree/main/docs/dev/debt) file
- [ ] No notes, investigation `.md` files or images added to the repository (attach them to this PR)
- [ ] New third-party code is a submodule built from source
- [ ] Generic behaviour, not specific to one title
- [ ] Depends on: <!-- #PR, or none -->
- [ ] Unblocks: <!-- title ID and Game bring-up discussion, e.g. PPSA01325 #3232, or none -->
- [ ] GPUs tested: <!-- for AGC, shader recompiler or VideoOut changes: vendor, model, driver and OS of each GPU the GPU tests ran on; otherwise n/a -->
- [ ] AI-assisted: <!-- yes / no -->

View File

@ -14,16 +14,34 @@ jobs:
contents: read
pull-requests: write
steps:
- uses: actions/cache/restore@v6
with:
path: ${{ runner.temp }}/area-state.json
key: area-labels-${{ github.run_id }}
restore-keys: area-labels-
- id: prs
env:
GH_TOKEN: ${{ github.token }}
run: |
state=$RUNNER_TEMP/area-state.json
[ -s "$state" ] || echo '{}' > "$state"
config=$(gh api "repos/$GITHUB_REPOSITORY/contents/.github/labeler.yml" --jq .sha)
gh pr list -R "$GITHUB_REPOSITORY" --base "${{ github.event.repository.default_branch }}" -L 200 --json number,headRefOid \
--jq "map({key: (.number | tostring), value: (.headRefOid + \"-$config\")}) | from_entries" > "$RUNNER_TEMP/area-open.json"
jq -r --slurpfile old "$state" 'to_entries[] | select($old[0][.key] != .value) | .key' "$RUNNER_TEMP/area-open.json" | head -n 40 > "$RUNNER_TEMP/area-todo"
jq -c --slurpfile open "$RUNNER_TEMP/area-open.json" --rawfile todo "$RUNNER_TEMP/area-todo" \
'with_entries(select(.key | in($open[0]))) + ($open[0] | with_entries(select(.key | IN($todo | split("\n")[]))))' "$state" > "$RUNNER_TEMP/area-next.json"
{
echo 'numbers<<EOF'
gh pr list -R "$GITHUB_REPOSITORY" --base "${{ github.event.repository.default_branch }}" -L 200 --json number --jq '.[].number'
cat "$RUNNER_TEMP/area-todo"
echo EOF
} >> "$GITHUB_OUTPUT"
- if: steps.prs.outputs.numbers != ''
uses: actions/labeler@v7
with:
pr-number: ${{ steps.prs.outputs.numbers }}
- run: mv "$RUNNER_TEMP/area-next.json" "$RUNNER_TEMP/area-state.json"
- uses: actions/cache/save@v6
with:
path: ${{ runner.temp }}/area-state.json
key: area-labels-${{ github.run_id }}

View File

@ -4,14 +4,26 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pr:
description: Pull request number to build
required: true
type: string
linux:
description: Also build and test on Linux
required: false
default: true
type: boolean
permissions:
contents: read
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
group: build-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr || github.ref }}
cancel-in-progress: ${{ github.event_name != 'push' }}
env:
CONFIGURE: >-
@ -20,34 +32,111 @@ env:
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
jobs:
changes:
if: github.event_name == 'pull_request'
eligibility:
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
outputs:
relinker: ${{ steps.filter.outputs.relinker }}
code: ${{ steps.filter.outputs.code }}
sha: ${{ steps.gate.outputs.sha }}
pr: ${{ steps.gate.outputs.pr }}
head: ${{ steps.gate.outputs.head }}
relinker: ${{ steps.gate.outputs.relinker }}
register-context: ${{ steps.gate.outputs.register-context }}
write-watch: ${{ steps.gate.outputs.write-watch }}
full: ${{ steps.gate.outputs.full }}
steps:
- uses: dorny/paths-filter@v4
id: filter
- uses: actions/github-script@v8
id: gate
env:
PR_NUMBER: ${{ inputs.pr }}
with:
predicate-quantifier: some-with-excludes
filters: |
relinker:
- 'core/relinker/**'
- 'core/libs/prx/libc/src/specifics/windows/**'
- 'CMakeLists.txt'
- '.github/workflows/build.yml'
code:
- '**'
- '!**/*.md'
- '!docs/**'
script: |
if (context.eventName === 'push') {
if (context.ref !== 'refs/heads/main') {
throw new Error('Automatic full builds only run on main');
}
core.setOutput('sha', context.sha);
core.setOutput('pr', '');
core.setOutput('head', '');
core.setOutput('relinker', true);
core.setOutput('register-context', true);
core.setOutput('write-watch', true);
core.setOutput('full', true);
await core.summary.addRaw(`Building main at ${context.sha}: all builds and tests enabled`).write();
return;
}
const { owner, repo } = context.repo;
const manual = context.eventName === 'workflow_dispatch';
if (manual) {
for (const username of new Set([context.actor, process.env.GITHUB_TRIGGERING_ACTOR])) {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ owner, repo, username });
if (!['write', 'maintain', 'admin'].includes(data.permission)) {
throw new Error('Only collaborators with write access can start or rerun builds');
}
}
if (!/^[1-9][0-9]*$/.test(process.env.PR_NUMBER)) {
throw new Error('Enter a positive pull request number');
}
}
const pull_number = manual ? Number(process.env.PR_NUMBER) : context.payload.pull_request.number;
if (!Number.isSafeInteger(pull_number) || pull_number < 1) {
throw new Error('Invalid pull request number');
}
let { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
for (let attempt = 0; pr.mergeable === null && attempt < 10; ++attempt) {
await new Promise((resolve) => setTimeout(resolve, 3000));
({ data: pr } = await github.rest.pulls.get({ owner, repo, pull_number }));
}
if (pr.state !== 'open' || pr.base.ref !== 'main') {
throw new Error('The pull request must be open and target main');
}
if (!manual && pr.head.sha !== context.payload.pull_request.head.sha) {
throw new Error('The pull request has newer commits; use the latest run');
}
if (pr.mergeable === false) {
throw new Error('The pull request does not merge cleanly into main; rebase it first');
}
let relinker = manual;
if (!manual) {
const { data: commits } = await github.rest.repos.listCommits({
owner, repo, sha: 'main', author: pr.user.login, per_page: 1
});
relinker = commits.length > 0;
}
const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number, per_page: 100 });
const paths = files.flatMap((file) => [file.filename, file.previous_filename].filter(Boolean));
const touches = (...prefixes) => files.length >= 3000 ||
paths.some((path) => prefixes.some((prefix) => prefix.endsWith('/') ? path.startsWith(prefix) : path === prefix));
const workflow = '.github/workflows/build.yml';
const libc = 'core/libs/prx/libc/';
relinker = relinker && touches(
'core/relinker/', libc, 'core/libs/prx/libkernel/AppMetadata/', 'core/libs/tests/ParamJsonParser.cpp',
'core/shader/recompiler/tests/CacheFileReadTests.cpp', 'core/shader/recompiler/ShaderCacheDirectory.hpp',
'tools/', 'cmake/', 'CMakeLists.txt', workflow
);
const registerContext = touches('core/libs/tests/register_context/', 'core/libs/tests/RegisterContext.cpp', libc, workflow);
const writeWatch = touches('core/libs/tests/write_watch/', 'core/libs/tests/WriteWatch.cpp', libc, workflow);
const { data: main } = await github.rest.repos.getBranch({ owner, repo, branch: 'main' });
core.setOutput('sha', main.commit.sha);
core.setOutput('pr', String(pull_number));
core.setOutput('head', pr.head.sha);
core.setOutput('relinker', relinker);
core.setOutput('register-context', registerContext);
core.setOutput('write-watch', writeWatch);
core.setOutput('full', manual);
core.info(`PR #${pull_number} at ${pr.head.sha} merged into main at ${main.commit.sha}`);
await core.summary.addRaw(
`PR #${pull_number} at ${pr.head.sha} merged into main at ${main.commit.sha}: full builds ${manual ? 'enabled' : 'disabled'}, ` +
`relinker ${relinker ? 'enabled' : 'skipped: no relinker file changed or the author has no commit in main'}, ` +
`register context tests ${registerContext ? 'enabled' : 'skipped'}, write watch tests ${writeWatch ? 'enabled' : 'skipped'}`
).write();
relinker:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.relinker == 'true') }}
needs: eligibility
if: ${{ needs.eligibility.outputs.relinker == 'true' }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
@ -68,6 +157,19 @@ jobs:
shell: bash
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
- name: Merge the pull request into main
if: ${{ needs.eligibility.outputs.head != '' }}
shell: bash
env:
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
PR_HEAD: ${{ needs.eligibility.outputs.head }}
run: |
git fetch --no-tags --unshallow origin "refs/pull/$PR_NUMBER/head"
if [ "$(git rev-parse FETCH_HEAD)" != "$PR_HEAD" ]; then echo "::error::The pull request has newer commits; start a new build"; exit 1; fi
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit FETCH_HEAD; then echo "::error::The pull request does not merge cleanly into main; rebase it first"; exit 1; fi
- if: runner.os == 'Windows'
id: toolchain
uses: actions/cache@v6
@ -84,37 +186,91 @@ jobs:
- run: cmake --build build-relinker --parallel 3
- run: ctest --test-dir build-relinker --output-on-failure --timeout 120
register-context:
needs: eligibility
if: ${{ needs.eligibility.outputs.register-context == 'true' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-15-intel]
configuration: [Debug, Release]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
- run: cmake -S core/libs/tests/register_context -B build/register-context -DCMAKE_BUILD_TYPE=${{ matrix.configuration }}
- run: cmake --build build/register-context --parallel
- run: ctest --test-dir build/register-context --output-on-failure --repeat until-fail:3 --no-tests=error
write-watch:
needs: eligibility
if: ${{ needs.eligibility.outputs.write-watch == 'true' }}
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, macos-15]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
- run: cmake -S core/libs/tests/write_watch -B build/write-watch -DCMAKE_BUILD_TYPE=Release
- run: cmake --build build/write-watch --parallel
- run: ctest --test-dir build/write-watch --output-on-failure --repeat until-fail:3 --no-tests=error
linux:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.code == 'true') }}
needs: eligibility
if: ${{ (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.linux)) && needs.eligibility.outputs.full == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
submodules: true
- name: Merge the pull request into main
if: ${{ needs.eligibility.outputs.head != '' }}
shell: bash
env:
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
PR_HEAD: ${{ needs.eligibility.outputs.head }}
run: |
git fetch --no-tags --unshallow origin "refs/pull/$PR_NUMBER/head"
if [ "$(git rev-parse FETCH_HEAD)" != "$PR_HEAD" ]; then echo "::error::The pull request has newer commits; start a new build"; exit 1; fi
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit FETCH_HEAD; then echo "::error::The pull request does not merge cleanly into main; rebase it first"; exit 1; fi
git submodule update --init --recursive
- uses: hendrikmuhs/ccache-action@v1.2.24
with:
key: linux
save: false
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
evict-old-files: job
- name: Install lavapipe for the GPU execution tests
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libvulkan1 mesa-vulkan-drivers
- name: Install lavapipe and the SDL audio and XRandR development files
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libvulkan1 mesa-vulkan-drivers libpipewire-0.3-dev libpulse-dev libasound2-dev libxrandr-dev
- id: mesa
run: |
echo "version=$(dpkg-query -W -f='${Version}' mesa-vulkan-drivers)" >> "$GITHUB_OUTPUT"
echo "cpu=$(grep -m1 '^flags' /proc/cpuinfo | sha256sum | cut -c1-12)" >> "$GITHUB_OUTPUT"
- uses: actions/cache/restore@v6
with:
path: .mesa-shader-cache
key: mesa-${{ steps.mesa.outputs.version }}-${{ steps.mesa.outputs.cpu }}-${{ github.sha }}
restore-keys: mesa-${{ steps.mesa.outputs.version }}-${{ steps.mesa.outputs.cpu }}-
- run: cmake -S . -B build $CONFIGURE -DANYPS5_ENABLE_SPIRV_TOOLS=ON
- name: Check that every test executable is registered with ctest
run: python3 tools/check_test_registration.py build
- run: cmake --build build
- run: cmake --build build --target libs
- name: Save the compiler cache before the tests
if: github.event_name == 'push'
uses: actions/cache/save@v6
with:
path: ${{ github.workspace }}/.ccache
key: ccache-linux-${{ github.run_id }}-${{ github.run_attempt }}
- run: ctest --test-dir build --output-on-failure --timeout 120 ${{ github.event_name == 'push' && '--repeat until-fail:3' || '' }} --parallel 4 --output-log ctest.log
- run: ctest --test-dir build --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log --output-junit ctest.xml
env:
ANYPS5_REQUIRE_VULKAN: 1
GALLIUM_OVERRIDE_CPU_CAPS: avx
MESA_SHADER_CACHE_DIR: ${{ github.workspace }}/.mesa-shader-cache
- if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && !cancelled() }}
uses: actions/cache/save@v6
with:
path: .mesa-shader-cache
key: mesa-${{ steps.mesa.outputs.version }}-${{ steps.mesa.outputs.cpu }}-${{ github.sha }}
- run: python3 tools/check_skips.py build/ctest.xml
- name: Report tests slower than 30 s
if: ${{ !cancelled() }}
shell: bash
@ -124,8 +280,8 @@ jobs:
END { for (name in max) if (max[name] > 30) printf "::warning title=Slow test::%s took %.1f s on %s; tests must finish in 30 s (CONTRIBUTING.md)\n", name, max[name], ENVIRON["RUNNER_OS"] }' ctest.log
windows:
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.code == 'true') }}
needs: eligibility
if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.eligibility.outputs.full == 'true' }}
runs-on: windows-latest
timeout-minutes: 45
env:
@ -138,7 +294,20 @@ jobs:
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.eligibility.outputs.sha }}
persist-credentials: false
submodules: true
- name: Merge the pull request into main
if: ${{ needs.eligibility.outputs.head != '' }}
shell: bash
env:
PR_NUMBER: ${{ needs.eligibility.outputs.pr }}
PR_HEAD: ${{ needs.eligibility.outputs.head }}
run: |
git fetch --no-tags --unshallow origin "refs/pull/$PR_NUMBER/head"
if [ "$(git rev-parse FETCH_HEAD)" != "$PR_HEAD" ]; then echo "::error::The pull request has newer commits; start a new build"; exit 1; fi
if ! git -c user.name=ci -c user.email=ci@localhost merge --no-ff --no-edit FETCH_HEAD; then echo "::error::The pull request does not merge cleanly into main; rebase it first"; exit 1; fi
git submodule update --init --recursive
- id: toolchain
uses: actions/cache@v6
with:
@ -152,10 +321,10 @@ jobs:
- uses: hendrikmuhs/ccache-action@v1.2.24
with:
key: windows
save: false
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
evict-old-files: job
- shell: cmd
run: cmake -S . -B build %CONFIGURE%
run: cmake -S . -B build %CONFIGURE% "-DANYPS5_AGC_EXECUTION_TESTS=F16ToF32Unpack;F64FmaSubnormals;RegistrationPrepareShutdown"
- name: Check that every test executable is registered with ctest
shell: cmd
run: python tools/check_test_registration.py build
@ -163,14 +332,9 @@ jobs:
run: cmake --build build
- shell: cmd
run: cmake --build build --target libs
- name: Save the compiler cache before the tests
if: github.event_name == 'push'
uses: actions/cache/save@v6
with:
path: ${{ github.workspace }}\.ccache
key: ccache-windows-${{ github.run_id }}-${{ github.run_attempt }}
- shell: cmd
run: ctest --test-dir build --output-on-failure --timeout 120 ${{ github.event_name == 'push' && '--repeat until-fail:3' || '' }} --parallel 4 --output-log ctest.log
run: ctest --test-dir build --output-on-failure --timeout 120 --parallel 4 --output-log ctest.log --output-junit ctest.xml
- run: python tools/check_skips.py build/ctest.xml --job windows
- name: Report tests slower than 30 s
if: ${{ !cancelled() }}
shell: bash

View File

@ -9,6 +9,10 @@ on:
permissions: {}
concurrency:
group: conflict-label
cancel-in-progress: true
jobs:
label:
runs-on: ubuntu-latest

View File

@ -1,14 +1,14 @@
name: Conventions
on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened, edited]
permissions:
contents: read
concurrency:
group: conventions-${{ github.ref }}
group: conventions-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
@ -18,5 +18,15 @@ jobs:
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
- run: python3 tools/check_conventions.py --base ${{ github.event.pull_request.base.sha }} --head ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Fetch pull request objects without checking out its code
env:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: git fetch --no-tags origin "$HEAD_SHA"
- name: Check conventions with the trusted base script
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 -I tools/check_conventions.py --base "$BASE_SHA" --head "$HEAD_SHA"

View File

@ -19,10 +19,12 @@ jobs:
GH_REPO: ${{ github.repository }}
steps:
- run: |
label() { gh label create "$1" --color "$2" --description "$3"; }
existing=$(gh label list --limit 1000 --json name --jq '.[].name')
label() { grep -qixF -- "$1" <<< "$existing" || gh label create "$1" --color "$2" --description "$3"; }
force_label() { gh label create "$1" --color "$2" --description "$3" --force; }
force_label 'needs rebase' b60205 'Conflicts with main, rebase needed'
force_label 'open PR limit' d93f0b 'Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20'
force_label ci 5319e7 '.github'
force_label agc 1d76db 'libSceAgc*'
force_label shader 1d76db 'core/shader'
@ -33,3 +35,4 @@ jobs:
label prx c5def5 'Other PRX libraries'
label build bfd4f2 'CMake, submodules, 3rdparty'
label docs 0075ca 'Documentation'
label stale ededed 'Conflicting with main and no activity for 7 days'

55
.github/workflows/pages.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Pages
on:
push:
branches: [main]
workflow_dispatch:
release:
types: [published]
workflow_run:
workflows: [Release]
types: [completed]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
pages:
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v7
with:
ref: main
fetch-depth: 0
- name: Build web converter
shell: bash
run: |
git clone --depth 1 https://github.com/emscripten-core/emsdk.git "$RUNNER_TEMP/emsdk"
"$RUNNER_TEMP/emsdk/emsdk" install 6.0.3
"$RUNNER_TEMP/emsdk/emsdk" activate 6.0.3
source "$RUNNER_TEMP/emsdk/emsdk_env.sh"
emcmake cmake -S . -B build-wasm -DANYPS5_BUILD_WASM=ON -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
cmake --build build-wasm --target relinker_web --parallel 2
- name: Test web converter
run: python3 tools/test_web.py --build build-wasm
- name: Download latest release libraries
env:
GITHUB_TOKEN: ${{ github.token }}
run: python3 tools/build_web.py --build build-wasm --libraries
- run: python3 tools/progress.py build-wasm/web
- run: python3 tools/progress_history.py build-wasm/web
- uses: actions/upload-pages-artifact@v5
with:
path: build-wasm/web
- id: deployment
uses: actions/deploy-pages@v5

77
.github/workflows/pr-intake.yml vendored Normal file
View File

@ -0,0 +1,77 @@
name: PR intake
on:
pull_request_target:
branches: [main]
types: [opened, reopened]
permissions: {}
concurrency:
group: pr-intake-${{ github.event.pull_request.number }}
jobs:
intake:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/github-script@v8
with:
script: |
const { owner, repo } = context.repo;
const pull_number = context.payload.pull_request.number;
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
if (pr.state !== 'open' || pr.base.ref !== 'main') {
return;
}
const { data: mergedPRs } = await github.rest.search.issuesAndPullRequests({
q: `repo:${owner}/${repo} is:pr is:merged base:main author:${pr.user.login}`,
per_page: 1
});
if (mergedPRs.incomplete_results || !Number.isSafeInteger(mergedPRs.total_count) || mergedPRs.total_count < 0) {
throw new Error('Could not reliably count merged pull requests');
}
const merged = mergedPRs.total_count;
if (merged >= 20) {
return;
}
const allowedOpen = merged >= 1 ? 20 : 1;
const openPRs = await github.paginate(github.rest.pulls.list, {
owner, repo, state: 'open', base: 'main', per_page: 100
});
const open = new Set(openPRs.filter((p) => p.user.login === pr.user.login).map((p) => p.number));
open.add(pull_number);
if (open.size <= allowedOpen) {
return;
}
const name = 'open PR limit';
try {
await github.rest.issues.getLabel({ owner, repo, name });
} catch (error) {
if (error.status !== 404) {
throw error;
}
try {
await github.rest.issues.createLabel({
owner, repo, name, color: 'd93f0b',
description: 'Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20'
});
} catch (createError) {
if (createError.status !== 422) {
throw createError;
}
await github.rest.issues.getLabel({ owner, repo, name });
}
}
await github.rest.issues.addLabels({ owner, repo, issue_number: pull_number, labels: [name] });
const body = 'Thank you for your contribution! Authors with no pull requests merged into `main` can have 1 open pull request at a time, authors with at least 1 merged can have 20, and from 20 merged there is no limit. This PR has been automatically closed and labeled "open PR limit" because that limit was reached. This is not a judgment of the quality of your changes: reopen it once one of your open pull requests is merged or closed.';
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number: pull_number, per_page: 100
});
if (!comments.some((comment) => comment.user.login === 'github-actions[bot]' && comment.body === body)) {
await github.rest.issues.createComment({ owner, repo, issue_number: pull_number, body });
}
await github.rest.pulls.update({ owner, repo, pull_number, state: 'closed' });

View File

@ -22,15 +22,30 @@ jobs:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/cache/restore@v6
with:
path: ${{ runner.temp }}/overlap-state.json
key: pr-overlap-${{ github.run_id }}
restore-keys: pr-overlap-
- env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
out=$RUNNER_TEMP/overlap
state=$RUNNER_TEMP/overlap-state.json
python3 tools/pr_overlap.py --base "${{ github.event.repository.default_branch }}" --out "$out"
[ -s "$state" ] || echo '{}' > "$state"
record() { jq --arg pr "$1" --arg h "$2" '.[$pr] = $h' "$state" > "$state.new" && mv "$state.new" "$state"; }
shopt -s nullglob
marker='<!-- pr-overlap -->'
prev=
for file in "$out"/*.md; do
[ -z "$prev" ] || record "$prev" "$hash"
pr=$(basename "$file" .md)
hash=$(sha256sum "$file" | cut -d' ' -f1)
prev=
[ "$(jq -r --arg pr "$pr" '.[$pr] // empty' "$state")" = "$hash" ] && continue
prev=$pr
comment=$(gh api "repos/$GH_REPO/issues/$pr/comments" --paginate \
--jq ".[] | select(.user.login == \"github-actions[bot]\" and (.body | startswith(\"$marker\"))) | [.id, .body] | @json" | head -n1)
id=$(jq -r '.[0] // empty' <<< "${comment:-null}")
@ -45,3 +60,11 @@ jobs:
gh api -X DELETE "repos/$GH_REPO/issues/comments/$id"
fi
done
[ -z "$prev" ] || record "$prev" "$hash"
reports=$(for file in "$out"/*.md; do basename "$file" .md; done | jq -R . | jq -sc .)
jq -c --argjson keep "$reports" 'with_entries(select(.key | IN($keep[])))' "$state" > "$state.new" && mv "$state.new" "$state"
- if: always()
uses: actions/cache/save@v6
with:
path: ${{ runner.temp }}/overlap-state.json
key: pr-overlap-${{ github.run_id }}

View File

@ -1,30 +0,0 @@
name: Progress
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
progress:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v7
- run: python3 tools/progress.py out
- uses: actions/upload-pages-artifact@v5
with:
path: out
- id: deployment
uses: actions/deploy-pages@v5

View File

@ -49,6 +49,8 @@ jobs:
path: C:\winlibs
key: ${{ env.WINLIBS_ZIP }}
- if: matrix.platform == 'windows' && steps.toolchain.outputs.cache-hit != 'true'
env:
SSL_CERT_FILE: 'C:\Program Files\Git\mingw64\etc\ssl\certs\ca-bundle.crt'
run: |
curl -sSfL -o "$RUNNER_TEMP/winlibs.zip" "https://github.com/brechtsanders/winlibs_mingw/releases/download/$WINLIBS_RELEASE/$WINLIBS_ZIP"
7z x "$RUNNER_TEMP/winlibs.zip" -oC:/winlibs
@ -58,12 +60,17 @@ jobs:
with:
key: ${{ matrix.platform }}
save: false
- name: Install lavapipe for the GPU execution tests and the audio development files
if: matrix.platform == 'linux'
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libvulkan1 mesa-vulkan-drivers libpipewire-0.3-dev libpulse-dev libasound2-dev libxrandr-dev
- name: Configure Linux
if: matrix.platform == 'linux'
run: cmake -S . -B build $CONFIGURE
- name: Configure Windows
if: matrix.platform == 'windows'
shell: cmd
env:
SSL_CERT_FILE: 'C:\Program Files\Git\mingw64\etc\ssl\certs\ca-bundle.crt'
run: cmake -S . -B build %CONFIGURE%
- name: Build project and tests (Linux)
if: matrix.platform == 'linux'
@ -75,6 +82,9 @@ jobs:
- name: Run tests (Linux)
if: matrix.platform == 'linux'
run: ctest --test-dir build --output-on-failure --timeout 120 --stop-on-failure --no-tests=error
env:
ANYPS5_REQUIRE_VULKAN: 1
GALLIUM_OVERRIDE_CPU_CAPS: avx
- name: Run tests (Windows)
if: matrix.platform == 'windows'
shell: cmd

28
.github/workflows/stale-conflicts.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Stale conflicts
on:
schedule:
- cron: '30 3 * * *'
workflow_dispatch:
permissions: {}
jobs:
warn:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v11
with:
only-pr-labels: needs rebase
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 7
days-before-pr-close: -1
stale-pr-label: stale
stale-pr-message: 'This pull request has conflicted with `main` and had no activity for 7 days. Rebase it on current `main` so it can be reviewed and merged. It will not be closed automatically.'
remove-pr-stale-when-updated: true
exempt-draft-pr: true
operations-per-run: 200

6
.gitmodules vendored
View File

@ -28,6 +28,12 @@
[submodule "3rdparty/stb"]
path = 3rdparty/stb
url = https://github.com/nothings/stb.git
[submodule "3rdparty/tracy"]
path = 3rdparty/tracy
url = https://github.com/wolfpld/tracy.git
[submodule "3rdparty/libjpeg-turbo"]
path = 3rdparty/libjpeg-turbo
url = https://github.com/libjpeg-turbo/libjpeg-turbo.git
[submodule "3rdparty/libusb-cmake"]
path = 3rdparty/libusb-cmake
url = https://github.com/libusb/libusb-cmake.git

1
3rdparty/libusb-cmake vendored Submodule

@ -0,0 +1 @@
Subproject commit bea6567b63796ab27c1c33257d230284fb2d8316

1
3rdparty/tracy vendored Submodule

@ -0,0 +1 @@
Subproject commit 30997d5ca6bb632cc10807a1da8a6d3de0aeeb3c

View File

@ -10,6 +10,19 @@ endfunction()
option(BUILD_TESTING "Build and register relinker tests" OFF)
option(ANYPS5_RELINKER_ONLY "Build the relinker without system libraries or third-party dependencies" OFF)
option(ANYPS5_BUILD_WASM "Build the browser relinker" OFF)
if(ANYPS5_BUILD_WASM)
if(NOT EMSCRIPTEN)
message(FATAL_ERROR "ANYPS5_BUILD_WASM requires emcmake and Emscripten")
endif()
if(BUILD_TESTING)
message(FATAL_ERROR "Use the native build for C++ tests and the browser tests for WASM")
endif()
set(ANYPS5_RELINKER_CLI OFF CACHE BOOL "Build the native relinker command line" FORCE)
add_subdirectory(core/relinker)
return()
endif()
if(BUILD_TESTING)
enable_testing()
if(MINGW)
@ -24,23 +37,104 @@ if(BUILD_TESTING)
endif()
option(ANYPS5_ENABLE_SPIRV_TOOLS "Enable SPIRV-Tools validation and optimization" OFF)
option(ANYPS5_ENABLE_ASAN "Build Linux targets with AddressSanitizer and use an ASan-compatible guest arena range" OFF)
option(APS5_ENABLE_TIMING_LOG "Write frame timings asynchronously to frame-timing.log" OFF)
option(APS5_ENABLE_TRACY "Build the Tracy profiler client and report performance timer scopes as Tracy zones" OFF)
option(ANYPS5_USE_SYSTEM_DEPS "Resolve SDL2, freetype, Vulkan-Headers, SPIRV-Headers, glslang and SPIRV-Tools from the system instead of the bundled submodules" OFF)
add_compile_definitions(APS5_ENABLE_TIMING_LOG=$<BOOL:${APS5_ENABLE_TIMING_LOG}>)
include(cmake/SystemDeps.cmake)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT APPLE)
if(ANYPS5_ENABLE_ASAN)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(FATAL_ERROR "ANYPS5_ENABLE_ASAN is supported only on Linux")
endif()
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")
message(FATAL_ERROR "ANYPS5_ENABLE_ASAN requires GCC or Clang")
endif()
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
add_link_options(-fsanitize=address)
add_compile_definitions(ANYPS5_ENABLE_ASAN=1)
elseif(NOT APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
endif()
if(BUILD_TESTING)
add_test_executable(shader_cache_file_read_tests
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/tests/CacheFileReadTests.cpp)
target_include_directories(shader_cache_file_read_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler)
add_test(NAME shader_cache_file_read COMMAND shader_cache_file_read_tests)
set_tests_properties(shader_cache_file_read PROPERTIES TIMEOUT 20)
add_test_executable(request_serializer_tests
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/tests/RequestSerializerTests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp)
target_include_directories(request_serializer_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/ControlFlow/include)
add_test(NAME request_serializer COMMAND request_serializer_tests)
set_tests_properties(request_serializer PROPERTIES TIMEOUT 20)
find_package(Python3 QUIET COMPONENTS Interpreter)
if(Python3_Interpreter_FOUND)
add_test(NAME pr_overlap_encoding COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_encoding.py)
add_test(NAME pr_overlap_dependencies COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_dependencies.py)
add_test(NAME pr_overlap_tools COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap.py)
add_test(NAME progress_history COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_history.py)
add_test(NAME progress_report COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress.py)
add_test(NAME progress_encoding COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_encoding.py)
add_test(NAME progress_render_sliver COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_render_sliver.py)
add_test(NAME progress_wrappers COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_wrappers.py)
add_test(NAME progress_read_encoding COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_read_encoding.py)
add_test(NAME import_audit COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_import_audit.py)
add_test(NAME conventions_function_bodies COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_comments.py)
add_test(NAME conventions_wrapped_declarations COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py)
add_test(NAME conventions_ci_gate COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_ci_gate.py)
add_test(NAME test_registration COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_test_registration.py)
add_test(NAME check_skips COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_skips.py)
add_test(NAME stubgen COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_stubgen.py)
add_test(NAME debt_split COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_debt_split.py)
add_test(NAME stubgen_stdout_newlines COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_stubgen_stdout_newlines.py)
add_test(NAME hardware_oracle COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/hw-oracle/test_hw_oracle.py)
add_test(NAME pr_overlap_exports COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_exports.py)
add_test(NAME pr_overlap_wrapped_exports COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_wrapped_exports.py)
add_test(NAME pr_overlap_own_branch COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_own_branch.py)
add_test(NAME nid_database_cache COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_nid_names.py)
add_test(NAME release_package COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_package_release.py)
add_test(NAME pad_input COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pad_input.py)
set_tests_properties(pad_input PROPERTIES TIMEOUT 20)
add_test(NAME trace_digest COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_trace_digest.py)
add_test(NAME conventions_body_bom COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_body_bom.py)
add_test(NAME conventions_agent_files COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_agent_files.py)
endif()
endif()
@ -64,10 +158,28 @@ set(SDL_HAPTIC OFF CACHE BOOL "" FORCE)
set(SDL_HIDAPI ON CACHE BOOL "" FORCE)
set(SDL_SENSOR OFF CACHE BOOL "" FORCE)
set(SDL_STATIC_PIC ON CACHE BOOL "" FORCE)
set(ANYPS5_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "")
add_subdirectory(3rdparty/SDL2)
set(CMAKE_EXE_LINKER_FLAGS "${ANYPS5_EXE_LINKER_FLAGS}")
if(NOT ANYPS5_USE_SYSTEM_DEPS)
set(ANYPS5_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "")
add_subdirectory(3rdparty/SDL2)
set(CMAKE_EXE_LINKER_FLAGS "${ANYPS5_EXE_LINKER_FLAGS}")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
get_directory_property(ANYPS5_SDL_X11_XRANDR DIRECTORY 3rdparty/SDL2 DEFINITION HAVE_X11_XRANDR)
if(NOT ANYPS5_SDL_X11_XRANDR)
message(FATAL_ERROR "SDL has no XRandR support, so X11 display refresh rates cannot be queried. "
"Install libxrandr-dev (Debian, Ubuntu) or libXrandr-devel (Fedora), "
"enable SDL_X11_XRANDR, then rerun configuration.")
endif()
get_directory_property(ANYPS5_SDL_PIPEWIRE DIRECTORY 3rdparty/SDL2 DEFINITION HAVE_PIPEWIRE)
get_directory_property(ANYPS5_SDL_PULSEAUDIO DIRECTORY 3rdparty/SDL2 DEFINITION HAVE_PULSEAUDIO)
get_directory_property(ANYPS5_SDL_ALSA DIRECTORY 3rdparty/SDL2 DEFINITION HAVE_ALSA)
if(NOT ANYPS5_SDL_PIPEWIRE AND NOT ANYPS5_SDL_PULSEAUDIO AND NOT ANYPS5_SDL_ALSA)
message(FATAL_ERROR "SDL found no PipeWire, PulseAudio or ALSA development files, so audio output would be silent. "
"Install libpipewire-0.3-dev, libpulse-dev and libasound2-dev (Debian, Ubuntu) "
"or pipewire-devel, pulseaudio-libs-devel and alsa-lib-devel (Fedora), then rerun configuration.")
endif()
endif()
endif()
set(ARCHITECTURE x86_64)
add_subdirectory(3rdparty/ffmpeg-core)
if(MINGW)
@ -76,14 +188,33 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_options(ffmpeg INTERFACE LINKER:--exclude-libs,ALL)
endif()
if(APS5_ENABLE_TRACY)
include(cmake/Tracy.cmake)
endif()
set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE)
set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE)
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE)
set(SKIP_INSTALL_ALL ON CACHE BOOL "" FORCE)
add_subdirectory(3rdparty/freetype EXCLUDE_FROM_ALL)
set_target_properties(freetype PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(NOT ANYPS5_USE_SYSTEM_DEPS)
add_subdirectory(3rdparty/freetype EXCLUDE_FROM_ALL)
set_target_properties(freetype PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(WIN32)
get_target_property(freetypeSources freetype SOURCES)
list(FILTER freetypeSources EXCLUDE REGEX "ftver\\.rc$")
set_target_properties(freetype PROPERTIES SOURCES "${freetypeSources}")
endif()
endif()
set(LIBUSB_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(LIBUSB_INSTALL_TARGETS OFF CACHE BOOL "" FORCE)
set(LIBUSB_BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(LIBUSB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(LIBUSB_ENABLE_UDEV OFF CACHE BOOL "" FORCE)
add_subdirectory(3rdparty/libusb-cmake EXCLUDE_FROM_ALL)
set_target_properties(usb-1.0 PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(core/shader/recompiler)
add_subdirectory(core/Decoder/Jpeg)

View File

@ -5,13 +5,13 @@
- Follow the [coding conventions](docs/dev/CONVENTIONS.md): naming, no comments except [technical debt](docs/dev/TechnicalDebt.md), Conventional Commits.
- Every function either does exactly what it is supposed to or throws. Unimplemented exports call `NotImplemented_nid_no_patch(__func__)` (see [libSceAudioIn](core/libs/prx/libSceAudioIn/Export.cpp)).
- Pull requests that add or change shader instruction semantics say where they come from: measured on hardware (which GPU and what was checked, e.g. with the [hardware oracle](docs/dev/HW_ORACLE.md)) or the exact source (ISA section, LLVM, ACO or Mesa file). Reviewers check the semantics on hardware. Cases the source doesn't settle throw, and behaviour not verified on hardware is recorded in [technical debt](docs/dev/TechnicalDebt.md).
- A silent stub is allowed only when it unblocks a title and only affects the UI; add it to [silent stubs](docs/dev/TechnicalDebt.md#silent-stubs).
- A silent stub is allowed only when it unblocks a title and only affects the UI; add it under Silent stubs in its library's [technical debt](docs/dev/debt/) file.
- Missing imports fail at startup with a clear error; don't replace them with fallbacks that keep running.
- Implement the general behaviour of a function, not what one title happens to need.
- Don't add replacements for modules that titles ship themselves in `sce_module/`, `sce_modules/` or `prx/`: engine or middleware modules (Cohtml, FMOD, GOG Galaxy) and SDK libraries that only wrap other system libraries (NpCppWebApi over NpWebApi2). The relinker converts and loads the title's own module, and a host library with the same name is left out of `DT_NEEDED`. Only system libraries, which reach the kernel or the hardware, are reimplemented in [core/libs/prx](core/libs/prx).
- Avoid non-standard extensions (`__attribute__`, etc.) where standard C++ is enough. Helper symbols that must not become NIDs use the `_nid_no_patch` or `_nid_no_patch_cut` suffix.
- The relinker uses only the C++20 standard library.
- Third-party code is added as a submodule under `3rdparty/` and built from source, not found on the system.
- Third-party code is added as a submodule under `3rdparty/` and built from source, not found on the system. With `ANYPS5_USE_SYSTEM_DEPS=ON` the packages packaged by the distributions (SDL2, freetype, Vulkan-Headers, SPIRV-Headers, glslang and SPIRV-Tools) come from the system instead; that resolution lives in [cmake/SystemDeps.cmake](cmake/SystemDeps.cmake) and the default build never reads the system.
- Don't add tests that only check that a symbol is exported: a missing export already fails at startup.
- Each test finishes in 30 s on the CI runners, Vulkan tests included (Linux runs them on lavapipe), counting the first run with no shader cache. ctest runs in parallel there, so a slow test competes for the cores and times out on some runs and not others. Split or shrink a test that gets close instead of raising its timeout. CI reports every test over 30 s as a warning on the pull request.
@ -29,7 +29,17 @@ ctest --test-dir build --output-on-failure
Python 3 is optional; without it some relinker tests are not registered.
The Conventions check runs on every pull request and fails when a rule on this page is broken. It accepts code comments only when the pull request also changes [TechnicalDebt](docs/dev/TechnicalDebt.md), and only UTF-8 text files. Run it locally before pushing:
Every push to `main`, including a merged pull request, automatically runs full Linux and Windows builds and tests and the relinker matrix on Linux, Windows and macOS, using the pushed commit without contributor checks.
For pull requests, full Linux and Windows builds and tests run only when a collaborator with write access selects Actions > Build > Run workflow on `main` and enters an open pull request number targeting `main`. A collaborator can start the same manual run from the command line, replacing `1234` with the pull request number:
```
gh workflow run build.yml --repo boykopovar/AnyPS5 --ref main --field pr=1234
```
This manual run also builds and tests the relinker on Linux, Windows and macOS, regardless of the author's previous contributions or the changed files. The relinker matrix also runs automatically when a pull request targeting `main` is opened, updated or reopened, if its author already has a commit in `main` and it changes a file the relinker-only build uses; full builds never run automatically for pull requests. Every job that runs automatically for pull requests runs only when the pull request changes its files: a `paths` filter on the `pull_request` trigger, or `needs: eligibility` with an `if` on the files output it sets in `build.yml`. The Conventions check fails a workflow change that adds a job without one. All build jobs build the selected pull request merged into the current `main` (GitHub's merge commit), so a pull request that no longer merges cleanly must be rebased first. New commits require another manual run for full builds.
The Conventions check runs automatically for every contributor, including first-time contributors. It uses the base branch checker and reads pull request Git objects without executing pull request code. The Conventions check runs on every pull request and fails when a rule on this page is broken. It accepts code comments only when the pull request also changes [technical debt](docs/dev/TechnicalDebt.md), the index or a file in `docs/dev/debt/`, and only UTF-8 text files. Run it locally before pushing:
```
python3 tools/check_conventions.py --base origin/main
@ -40,13 +50,20 @@ python3 tools/check_conventions.py --base origin/main
The [pull request template](.github/pull_request_template.md) is the checklist for these rules.
- One branch per topic, based on current `main`. Follow-up work goes in a new pull request, not into an open one.
- Open pull requests per author are limited by how many of theirs are merged into `main`: 1 with none merged, 20 with at least 1, no limit from 20. A pull request opened or reopened over the limit is closed automatically; reopen it once another one is merged or closed.
- Before starting, check that no open pull request already implements the same functions.
- Keep the branch up to date with `main` and resolve conflicts yourself; rebasing and force-pushing is fine.
- If a pull request needs another one first, say so in the description (`Depends on #N`).
- A pull request that conflicts with `main` and has no activity for 7 days is labeled `stale` with a reminder. It is not closed.
- If a pull request needs another one first, say so on the checklist line (`Depends on: #N`; `none` otherwise).
- If a pull request fixes a stop or a wrong result seen on a title, name it on the checklist line with the title ID and its [Game bring-up](https://github.com/boykopovar/AnyPS5/discussions/categories/game-bring-up) discussion (`Unblocks: PPSA01325 #3232`; `none` otherwise). Reviewers review these first.
- Fixes a title needs go to `main` as pull requests. A Game bring-up discussion lists the open pull requests and local changes the title still needs; update the list when one is merged, closed or replaced.
- The PR overlap comment lists open pull requests that change the same lines or exports; agree with their authors which one goes first and declare it with `Depends on`.
- Run the tests before opening the pull request and describe what was tested (OS, title or homebrew).
- A pull request that claims a change in speed shows the summary lines of `main` and of the change, from the same machine and scene, and attaches the traces, captured as the [Performance report](.github/ISSUE_TEMPLATE/performance.yml) issue form describes. A slow scene is reported with the same form.
- Changes to the AGC driver, the shader recompiler or VideoOut name each GPU the GPU tests ran on (vendor, model, driver, OS) on the `GPUs tested` checklist line. CI runs these tests only on lavapipe, and hardware drivers fail where lavapipe and other vendors pass, so a reviewer can ask for a run on another vendor before merging.
- Investigation notes, reports, screenshots and logs go in the pull request, not in the repository. Images for documentation go in the [gist](https://gist.github.com/boykopovar/0e53f2e1426f29ecd41e3b51540b8a90) comments.
- Say whether the change was written with AI assistance. The author of the pull request is responsible for every line of it.
## Documentation
Text in the repository is dry, strict and concise. Record known gaps, unknown NIDs and signatures in [technical debt](docs/dev/TechnicalDebt.md) instead of new files.
Text in the repository is dry, strict and concise. Record known gaps, unknown NIDs and signatures in [technical debt](docs/dev/TechnicalDebt.md) instead of new files. An entry goes in `docs/dev/debt/<name>.md`, named after the first `core/` path it links (`<name>` for `core/libs/prx/<name>/...`, otherwise for `core/<name>/...`), under the same `###` sections as the index; entries that link neither stay in the index. A pull request whose `TechnicalDebt.md` change conflicts after the split rebases and runs `python3 tools/debt_split.py resolve` during the stopped rebase, which moves its added, edited and removed entries to their files; `python3 tools/debt_split.py split` moves entries left in the index.

View File

@ -2,29 +2,33 @@
Tool for automatic executables porting to Linux and Windows.
[**Web converter**](https://boykopovar.github.io/AnyPS5/) - files stay on your device.
![anyps5_collage1](https://github.com/user-attachments/assets/0f8e13e8-1cb7-4c69-8075-39978e138994)
[Discord](https://discord.gg/BHFztBPUe)
Includes a [relinker](core/relinker) that converts executable to the target system's native format and implementations of [system prx libraries](core/libs/prx) suitable for dynamic linking. No emulation or separate runtime process.
[Usage](docs/user/USAGE.md), [Build instructions](docs/dev/BUILD.md), [Architecture](docs/dev/ARCHITECTURE.md), [Technical debt of the project](docs/dev/TechnicalDebt.md), [code style conventions](docs/dev/CONVENTIONS.md), [contributing](CONTRIBUTING.md)
## Status
[![libraries](https://boykopovar.github.io/AnyPS5/badge-libraries.svg)](https://boykopovar.github.io/AnyPS5/) [![shaders](https://boykopovar.github.io/AnyPS5/badge-shaders.svg)](https://boykopovar.github.io/AnyPS5/)
[![libraries](https://boykopovar.github.io/AnyPS5/badge-libraries.svg)](https://boykopovar.github.io/AnyPS5/progress.html) [![shaders](https://boykopovar.github.io/AnyPS5/badge-shaders.svg)](https://boykopovar.github.io/AnyPS5/progress.html)
[![progress map](https://boykopovar.github.io/AnyPS5/progress.svg)](https://boykopovar.github.io/AnyPS5/)
[![progress map](https://boykopovar.github.io/AnyPS5/progress.svg)](https://boykopovar.github.io/AnyPS5/progress.html)
[Progress history](https://boykopovar.github.io/AnyPS5/history.html)
<sub>* System libraries: percentage of the functions known to the project so far (declared in [core/libs/prx](core/libs/prx)), not of every PS5 system function. The total grows as more functions are declared.</sub>
[List of verified games](docs/user/COMPATIBILITY.md)
Dreaming Sarah (2D platformer) runs at a stable 60 fps on a GTX 1050 Ti / i5-7500 3.4GHz.
Unsupported or unexpected states strictly throw `std::runtime_error`. `what()` is printed to stderr and the process terminates.
The [shader recompiler](core/shader/recompiler/Recompiler.cpp) successfully produces SPIR-V (validated via [Spirv-Tools](3rdparty/SPIRV-Tools) when built with `ANYPS5_ENABLE_SPIRV_TOOLS`).
## Compatibility
See the [game compatibility list](docs/user/COMPATIBILITY.md) for tested games and known issues.
Per-game progress (stage reached, open blockers, libraries and GPU coverage) is tracked on the [blocker map](https://alxcbtw.github.io/anyps5-roadmap/), a community project built from public GitHub data ([source](https://github.com/AlxcBTW/anyps5-roadmap)). Test reports go in the [Game bring-up](https://github.com/boykopovar/AnyPS5/discussions/categories/game-bring-up) discussions, one thread per title.
## Input mapping

118
cmake/SystemDeps.cmake Normal file
View File

@ -0,0 +1,118 @@
set(ANYPS5_VULKAN_HEADERS_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/Vulkan-Headers/include")
set(ANYPS5_SPIRV_HEADERS_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/SPIRV-Headers/include")
set(ANYPS5_SDL2_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/SDL2/include")
set(ANYPS5_GLSLANG_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/3rdparty/glslang")
set(ANYPS5_SPIRV_HEADERS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/SPIRV-Headers")
set(ANYPS5_GLSLANG_SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/glslang")
if(NOT ANYPS5_USE_SYSTEM_DEPS)
return()
endif()
include(CheckCXXSourceCompiles)
find_package(SDL2 CONFIG REQUIRED)
if(NOT TARGET SDL2::SDL2)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SDL2 was found but does not provide SDL2::SDL2")
endif()
add_library(SDL2-static INTERFACE)
target_link_libraries(SDL2-static INTERFACE SDL2::SDL2)
get_target_property(ANYPS5_SDL2_INCLUDE_DIR SDL2::SDL2 INTERFACE_INCLUDE_DIRECTORIES)
if(NOT ANYPS5_SDL2_INCLUDE_DIR)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SDL2::SDL2 exposes no INTERFACE_INCLUDE_DIRECTORIES")
endif()
set(ANYPS5_SDL2_PROBE_INCLUDES ${ANYPS5_SDL2_INCLUDE_DIR})
foreach(_dir IN LISTS ANYPS5_SDL2_INCLUDE_DIR)
list(APPEND ANYPS5_SDL2_PROBE_INCLUDES "${_dir}/SDL2")
endforeach()
list(REMOVE_DUPLICATES ANYPS5_SDL2_PROBE_INCLUDES)
set(CMAKE_REQUIRED_INCLUDES ${ANYPS5_SDL2_PROBE_INCLUDES})
check_cxx_source_compiles("#include \"SDL_config.h\"\n#ifndef SDL_JOYSTICK_HIDAPI\n#error SDL_JOYSTICK_HIDAPI is not defined\n#endif\nint main() { return 0; }" ANYPS5_SDL2_HAS_HIDAPI)
unset(CMAKE_REQUIRED_INCLUDES)
if(NOT ANYPS5_SDL2_HAS_HIDAPI)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: the system SDL2 does not define SDL_JOYSTICK_HIDAPI, so a DualSense gets no light bar, touchpad or trigger effects and the disk audio driver does not preserve the requested format; sdl2-compat (SDL3 underneath) and SDL2 builds with HIDAPI disabled both fail the pad and audio tests; install a real SDL2 2.x built with HIDAPI")
endif()
find_package(Freetype REQUIRED)
if(NOT TARGET Freetype::Freetype)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: freetype was found but does not provide Freetype::Freetype")
endif()
add_library(freetype INTERFACE)
target_link_libraries(freetype INTERFACE Freetype::Freetype)
find_package(VulkanHeaders CONFIG REQUIRED)
if(NOT TARGET Vulkan::Headers)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: Vulkan-Headers was found but does not provide Vulkan::Headers")
endif()
get_target_property(ANYPS5_VULKAN_HEADERS_INCLUDE_DIR Vulkan::Headers INTERFACE_INCLUDE_DIRECTORIES)
if(NOT ANYPS5_VULKAN_HEADERS_INCLUDE_DIR)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: Vulkan::Headers exposes no INTERFACE_INCLUDE_DIRECTORIES")
endif()
set(CMAKE_REQUIRED_INCLUDES ${ANYPS5_VULKAN_HEADERS_INCLUDE_DIR})
check_cxx_source_compiles("#include <vulkan/vulkan.h>\nint main() { VkPhysicalDeviceMaintenance8FeaturesKHR features{}; (void)features; return 0; }" ANYPS5_VULKAN_HAS_MAINTENANCE8)
unset(CMAKE_REQUIRED_INCLUDES)
if(NOT ANYPS5_VULKAN_HAS_MAINTENANCE8)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: the system Vulkan-Headers do not provide VkPhysicalDeviceMaintenance8FeaturesKHR (VK_KHR_maintenance8), which the agc driver uses; install Vulkan-Headers 1.4.310 or newer")
endif()
find_package(SPIRV-Headers CONFIG REQUIRED)
if(NOT TARGET SPIRV-Headers::SPIRV-Headers)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SPIRV-Headers was found but does not provide SPIRV-Headers::SPIRV-Headers")
endif()
get_target_property(ANYPS5_SPIRV_HEADERS_INCLUDE_DIR SPIRV-Headers::SPIRV-Headers INTERFACE_INCLUDE_DIRECTORIES)
if(NOT ANYPS5_SPIRV_HEADERS_INCLUDE_DIR)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SPIRV-Headers::SPIRV-Headers exposes no INTERFACE_INCLUDE_DIRECTORIES")
endif()
find_package(glslang CONFIG REQUIRED)
if(NOT TARGET glslang::glslang OR NOT TARGET glslang::SPIRV)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: glslang was found but does not provide glslang::glslang and glslang::SPIRV")
endif()
add_library(glslang INTERFACE)
target_link_libraries(glslang INTERFACE glslang::glslang)
add_library(SPIRV INTERFACE)
target_link_libraries(SPIRV INTERFACE glslang::SPIRV)
find_path(ANYPS5_GLSLANG_PUBLIC_INCLUDE_DIR NAMES glslang/Public/ShaderLang.h)
if(NOT ANYPS5_GLSLANG_PUBLIC_INCLUDE_DIR)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: glslang/Public/ShaderLang.h was not found; the glslang headers are incomplete")
endif()
set(ANYPS5_GLSLANG_SPIRV_INCLUDE_DIR "${ANYPS5_GLSLANG_PUBLIC_INCLUDE_DIR}/glslang")
if(NOT EXISTS "${ANYPS5_GLSLANG_SPIRV_INCLUDE_DIR}/SPIRV/GlslangToSpv.h")
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: ${ANYPS5_GLSLANG_SPIRV_INCLUDE_DIR}/SPIRV/GlslangToSpv.h was not found")
endif()
set(ANYPS5_GLSLANG_INCLUDE_DIRS "${ANYPS5_GLSLANG_PUBLIC_INCLUDE_DIR};${ANYPS5_GLSLANG_SPIRV_INCLUDE_DIR}")
find_program(ANYPS5_GLSLANG_STANDALONE_EXECUTABLE NAMES glslang glslangValidator)
if(NOT ANYPS5_GLSLANG_STANDALONE_EXECUTABLE)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: the glslang compiler (glslang or glslangValidator) was not found; install the glslang tools package")
endif()
add_executable(glslang-standalone IMPORTED GLOBAL)
set_target_properties(glslang-standalone PROPERTIES IMPORTED_LOCATION "${ANYPS5_GLSLANG_STANDALONE_EXECUTABLE}")
if(ANYPS5_ENABLE_SPIRV_TOOLS)
find_package(SPIRV-Tools-opt CONFIG REQUIRED)
if(NOT TARGET SPIRV-Tools-opt)
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SPIRV-Tools was found but does not provide SPIRV-Tools-opt")
endif()
if(NOT TARGET SPIRV-Tools-static)
if(TARGET SPIRV-Tools)
add_library(SPIRV-Tools-static INTERFACE)
target_link_libraries(SPIRV-Tools-static INTERFACE SPIRV-Tools)
else()
message(FATAL_ERROR "ANYPS5_USE_SYSTEM_DEPS: SPIRV-Tools was found but provides neither SPIRV-Tools-static nor SPIRV-Tools")
endif()
endif()
endif()
set(ANYPS5_SYSTEM_DEPS_STAMP "")
list(APPEND ANYPS5_SYSTEM_DEPS_PACKAGES VulkanHeaders SPIRV-Headers glslang)
if(ANYPS5_ENABLE_SPIRV_TOOLS)
list(APPEND ANYPS5_SYSTEM_DEPS_PACKAGES SPIRV-Tools-opt)
endif()
foreach(_package IN LISTS ANYPS5_SYSTEM_DEPS_PACKAGES)
set(_version "unknown")
if(DEFINED ${_package}_VERSION)
set(_version "${${_package}_VERSION}")
endif()
string(APPEND ANYPS5_SYSTEM_DEPS_STAMP " ${_package}=${_version}")
endforeach()

21
cmake/Tracy.cmake Normal file
View File

@ -0,0 +1,21 @@
set(TRACY_ENABLE ON CACHE BOOL "" FORCE)
set(TRACY_STATIC OFF CACHE BOOL "" FORCE)
set(TRACY_ON_DEMAND ON CACHE BOOL "" FORCE)
set(TRACY_ONLY_LOCALHOST ON CACHE BOOL "" FORCE)
set(TRACY_NO_CRASH_HANDLER ON CACHE BOOL "" FORCE)
set(TRACY_NO_CODE_TRANSFER ON CACHE BOOL "" FORCE)
set(TRACY_NO_SAMPLING ON CACHE BOOL "" FORCE)
set(TRACY_NO_SYSTEM_TRACING ON CACHE BOOL "" FORCE)
set(TRACY_NO_CALLSTACK ON CACHE BOOL "" FORCE)
set(TRACY_NO_FRAME_IMAGE ON CACHE BOOL "" FORCE)
set(TRACY_NO_VERIFY ON CACHE BOOL "" FORCE)
set(CMAKE_DISABLE_FIND_PACKAGE_rocprofiler-sdk ON)
add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/tracy ${CMAKE_BINARY_DIR}/3rdparty/tracy EXCLUDE_FROM_ALL)
if(MINGW)
target_sources(TracyClient PRIVATE ${CMAKE_CURRENT_LIST_DIR}/TracyThreadExit.cpp)
target_compile_definitions(TracyClient PRIVATE TRACY_DELAYED_INIT)
get_target_property(tracyInterfaceDefinitions TracyClient INTERFACE_COMPILE_DEFINITIONS)
list(FILTER tracyInterfaceDefinitions EXCLUDE REGEX "^(WINVER|_WIN32_WINNT)=")
set_target_properties(TracyClient PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${tracyInterfaceDefinitions}")
endif()

View File

@ -0,0 +1,3 @@
extern "C" int __cxa_thread_atexit(void (*)(void*), void*, void*) {
return 0;
}

View File

@ -138,9 +138,9 @@ std::optional<Header> ParseHeader(std::span<const std::uint8_t> png) {
while (png.size() - offset >= CHUNK_OVERHEAD) {
const std::uint32_t length = readBigEndian32(&png[offset]);
const std::uint8_t* type = &png[offset + 4];
if (length > png.size() - offset - CHUNK_OVERHEAD) break;
if (isChunkType(type, "tRNS")) header.hasTransparency = true;
if (isChunkType(type, "tRNS") || isChunkType(type, "IDAT") || isChunkType(type, "IEND")) break;
if (length > png.size() - offset - CHUNK_OVERHEAD) break;
offset += CHUNK_OVERHEAD + length;
}
return header;

View File

@ -153,6 +153,12 @@ int main() {
Require(paletteHeader.has_value());
Require(paletteHeader->width == 2 && paletteHeader->height == 2 && paletteHeader->bitDepth == 2);
Require(paletteHeader->colorType == Decoder::Png::ColorType::Palette && paletteHeader->hasTransparency);
for (const std::size_t size : {std::size_t{69}, std::size_t{71}}) {
const auto truncated = Decoder::Png::ParseHeader(std::span<const std::uint8_t>(PALETTE_TRNS, size));
Require(truncated.has_value() && !truncated->hasTransparency);
}
const auto completeTransparency = Decoder::Png::ParseHeader(std::span<const std::uint8_t>(PALETTE_TRNS, 73));
Require(completeTransparency.has_value() && completeTransparency->hasTransparency);
const auto palette = Decoder::Png::Decode(PALETTE_TRNS);
Require(palette.has_value());
Require(palette->pixels == std::vector<std::uint8_t>({255, 0, 0, 255, 0, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 128}));

View File

@ -3,6 +3,12 @@ if(NOT WIN32)
string(STRIP "${CMAKE_EXE_LINKER_FLAGS}" CMAKE_EXE_LINKER_FLAGS)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
include(CheckPIESupported)
check_pie_supported(LANGUAGES C CXX)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
add_executable(nid_patcher
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/Sha1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/NidCompute.cpp
@ -10,6 +16,7 @@ add_executable(nid_patcher
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/ExportExclusions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/ElfNidPatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/PeNidPatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/MachONidPatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/BinaryPatcherFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nid/src/main.cpp
)
@ -18,7 +25,14 @@ target_include_directories(nid_patcher PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nid/i
target_compile_features(nid_patcher PRIVATE cxx_std_20)
if(MINGW)
target_link_options(nid_patcher PRIVATE -static -static-libgcc -static-libstdc++)
target_link_options(nid_patcher PRIVATE -municode -static -static-libgcc -static-libstdc++)
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS -fno-asynchronous-unwind-tables)
check_cxx_source_compiles("#ifdef __USING_SJLJ_EXCEPTIONS__\n#error\n#endif\nint main() { return 0; }" ANYPS5_MINGW_DWARF_EXCEPTIONS)
unset(CMAKE_REQUIRED_FLAGS)
if(NOT ANYPS5_MINGW_DWARF_EXCEPTIONS)
message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} selects SjLj exceptions with -fno-asynchronous-unwind-tables; the libraries need DWARF unwinding. Use the MinGW-w64 toolchain listed in docs/dev/BUILD.md.")
endif()
add_compile_options(-fno-asynchronous-unwind-tables)
endif()
@ -46,6 +60,10 @@ set(LIBS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(${LIBC_DIR} ${CMAKE_CURRENT_BINARY_DIR}/prx/libc)
target_include_directories(libc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
configure_windows_unwind(libc)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_options(libc PRIVATE LINKER:-z,now)
target_link_options(libc INTERFACE LINKER:--no-as-needed)
endif()
set(UNPATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/libs/unpatched)
set(PATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/libs)
@ -91,9 +109,12 @@ foreach(LIB_DIR ${LIBS_DIRS})
endif()
if(LIB_NAME STREQUAL "libkernel")
target_link_libraries(${LIB_NAME} PRIVATE libc)
target_link_libraries(${LIB_NAME} PUBLIC libc)
else()
target_link_libraries(${LIB_NAME} PRIVATE libkernel libc)
target_link_libraries(${LIB_NAME} PRIVATE libkernel PUBLIC libc)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_options(${LIB_NAME} PRIVATE LINKER:-z,now)
endif()
if(WIN32 AND LIB_NAME STREQUAL "libSceNet")
target_link_libraries(${LIB_NAME} PRIVATE ws2_32)
@ -128,18 +149,195 @@ foreach(LIB_DIR ${LIBS_DIRS})
endif()
endforeach()
if(APS5_ENABLE_TRACY)
set_target_properties(TracyClient PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${UNPATCHED_DIR}
LIBRARY_OUTPUT_DIRECTORY ${UNPATCHED_DIR}
ARCHIVE_OUTPUT_DIRECTORY ${IMPLIB_DIR}
)
set(TRACY_CLIENT_COPIED ${CMAKE_CURRENT_BINARY_DIR}/TracyClient.copied)
add_custom_command(
OUTPUT ${TRACY_CLIENT_COPIED}
COMMAND ${CMAKE_COMMAND} -E make_directory ${PATCHED_DIR}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:TracyClient> ${PATCHED_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${TRACY_CLIENT_COPIED}
DEPENDS TracyClient
COMMENT "Copying the Tracy client next to the patched libraries"
)
list(APPEND PATCHED_OUTPUTS ${TRACY_CLIENT_COPIED})
endif()
add_custom_target(libs DEPENDS ${PATCHED_OUTPUTS})
if(BUILD_TESTING)
add_test_executable(guest_posix_scalar_io_tests tests/GuestPosixScalarIo.cpp)
target_include_directories(guest_posix_scalar_io_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_posix_scalar_io_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_posix_scalar_io_tests)
add_test(NAME guest_posix_scalar_io COMMAND guest_posix_scalar_io_tests)
if(WIN32)
set_tests_properties(guest_posix_scalar_io PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(nid_buffer_validation_tests nid/tests/BufferValidation.cpp)
target_include_directories(nid_buffer_validation_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nid/include)
target_compile_features(nid_buffer_validation_tests PRIVATE cxx_std_20)
if(MINGW)
target_compile_options(nid_buffer_validation_tests PRIVATE -fasynchronous-unwind-tables)
endif()
add_test(NAME nid_buffer_validation COMMAND nid_buffer_validation_tests)
set_tests_properties(nid_buffer_validation PROPERTIES TIMEOUT 10)
find_package(Python3 QUIET COMPONENTS Interpreter)
if(Python3_Interpreter_FOUND)
add_test(NAME nid_gnu_hash COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_gnu_hash.py $<TARGET_FILE:nid_patcher>)
add_test(NAME nid_patcher_macho COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_macho_nids.py $<TARGET_FILE:nid_patcher>)
add_test(NAME nid_patcher_native_paths COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_native_paths.py $<TARGET_FILE:nid_patcher>)
set_tests_properties(nid_patcher_native_paths PROPERTIES TIMEOUT 20)
endif()
add_test_executable(patched_libraries_tests tests/PatchedLibraries.cpp)
add_dependencies(patched_libraries_tests libs)
if(Python3_Interpreter_FOUND)
add_test(NAME nid_pe_references COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_pe_references.py $<TARGET_FILE:nid_patcher>)
endif()
if(MINGW)
target_compile_options(patched_libraries_tests PRIVATE -fasynchronous-unwind-tables)
target_link_options(patched_libraries_tests PRIVATE -static -static-libgcc -static-libstdc++)
endif()
add_test(NAME patched_libraries COMMAND patched_libraries_tests ${PATCHED_DIR})
if(Python3_Interpreter_FOUND)
add_test(NAME nid_elf_layout COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_elf_layout.py $<TARGET_FILE:nid_patcher>)
endif()
add_test_executable(guest_kernel_sys_tests tests/GuestKernelSys.cpp)
target_include_directories(guest_kernel_sys_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_kernel_sys_tests PRIVATE libkernel_sys libkernel libc)
configure_windows_unwind(guest_kernel_sys_tests)
add_test(NAME guest_kernel_sys COMMAND guest_kernel_sys_tests)
if(Python3_Interpreter_FOUND)
add_test(NAME nid_verneed COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_verneed.py $<TARGET_FILE:nid_patcher>)
endif()
if(WIN32)
set_tests_properties(guest_kernel_sys PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
endif()
if(APPLE)
add_subdirectory(tests/write_watch)
endif()
if(WIN32)
add_test_executable(windows_write_watch_tests tests/WindowsWriteWatch.cpp)
target_include_directories(windows_write_watch_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(windows_write_watch_tests PRIVATE _WIN32_WINNT=0x0A00)
if(MINGW)
target_compile_options(windows_write_watch_tests PRIVATE -fasynchronous-unwind-tables)
endif()
add_test(NAME windows_write_watch COMMAND windows_write_watch_tests)
set_tests_properties(windows_write_watch PROPERTIES TIMEOUT 20)
endif()
add_test_executable(guest_offline_imports_tests tests/GuestOfflineImports.cpp)
target_include_directories(guest_offline_imports_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_offline_imports_tests PRIVATE libSceHttp libSceNpEntitlementAccess libSceRudp libc)
configure_windows_unwind(guest_offline_imports_tests)
add_test(NAME guest_offline_imports COMMAND guest_offline_imports_tests)
if(Python3_Interpreter_FOUND)
add_test(NAME nid_shared_strings COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/nid/tests/test_shared_strings.py $<TARGET_FILE:nid_patcher>)
endif()
if(WIN32)
set_tests_properties(guest_offline_imports PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceHttp>")
endif()
add_test_executable(guest_signin_dialog_tests tests/GuestSigninDialog.cpp)
target_include_directories(guest_signin_dialog_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_signin_dialog_tests PRIVATE libSceSigninDialog libc)
configure_windows_unwind(guest_signin_dialog_tests)
add_test(NAME guest_signin_dialog COMMAND guest_signin_dialog_tests)
if(WIN32)
set_tests_properties(guest_signin_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSigninDialog>")
endif()
add_test_executable(guest_netctl_ap_dialog_tests tests/GuestNetCtlApDialog.cpp)
target_include_directories(guest_netctl_ap_dialog_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_netctl_ap_dialog_tests PRIVATE libSceNetCtlApDialog libc)
configure_windows_unwind(guest_netctl_ap_dialog_tests)
add_test(NAME guest_netctl_ap_dialog COMMAND guest_netctl_ap_dialog_tests)
if(WIN32)
set_tests_properties(guest_netctl_ap_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNetCtlApDialog>")
endif()
add_test_executable(guest_np_auth_tests tests/GuestNpAuth.cpp)
target_include_directories(guest_np_auth_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_np_auth_tests PRIVATE libSceNpAuth libc)
configure_windows_unwind(guest_np_auth_tests)
add_test(NAME guest_np_auth COMMAND guest_np_auth_tests)
if(WIN32)
set_tests_properties(guest_np_auth PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpAuth>")
endif()
add_test_executable(guest_rudp_status_tests tests/GuestRudpStatus.cpp)
target_include_directories(guest_rudp_status_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_rudp_status_tests PRIVATE libSceRudp libc)
configure_windows_unwind(guest_rudp_status_tests)
add_test(NAME guest_rudp_status COMMAND guest_rudp_status_tests)
if(WIN32)
set_tests_properties(guest_rudp_status PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceRudp>")
endif()
add_test_executable(guest_rudp_context_queries_tests tests/GuestRudpContextQueries.cpp)
target_include_directories(guest_rudp_context_queries_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_rudp_context_queries_tests PRIVATE libSceRudp libc)
configure_windows_unwind(guest_rudp_context_queries_tests)
add_test(NAME guest_rudp_context_queries COMMAND guest_rudp_context_queries_tests)
if(WIN32)
set_tests_properties(guest_rudp_context_queries PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceRudp>")
endif()
add_test_executable(guest_rudp_pump_tests tests/GuestRudpPump.cpp)
target_include_directories(guest_rudp_pump_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_rudp_pump_tests PRIVATE libSceRudp libc)
configure_windows_unwind(guest_rudp_pump_tests)
add_test(NAME guest_rudp_pump COMMAND guest_rudp_pump_tests)
if(WIN32)
set_tests_properties(guest_rudp_pump PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceRudp>")
endif()
add_test_executable(guest_memory_pool_stats_tests tests/GuestMemoryPoolStats.cpp)
target_include_directories(guest_memory_pool_stats_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_memory_pool_stats_tests PRIVATE libSceSsl libSceHttp2 libSceNet libkernel libc)
configure_windows_unwind(guest_memory_pool_stats_tests)
add_test(NAME guest_memory_pool_stats COMMAND guest_memory_pool_stats_tests)
if(WIN32)
set_tests_properties(guest_memory_pool_stats PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSsl>")
endif()
add_test_executable(guest_system_gesture_tests tests/GuestSystemGesture.cpp)
target_include_directories(guest_system_gesture_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_system_gesture_tests PRIVATE libSceSystemGesture libc)
configure_windows_unwind(guest_system_gesture_tests)
add_test(NAME guest_system_gesture COMMAND guest_system_gesture_tests)
if(WIN32)
set_tests_properties(guest_system_gesture PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSystemGesture>")
endif()
if(UNIX AND (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$" OR CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64"))
add_subdirectory(tests/register_context)
endif()
add_test_executable(savedata_memory_metadata_tests tests/SaveDataMemoryMetadata.cpp)
target_include_directories(savedata_memory_metadata_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(savedata_memory_metadata_tests PRIVATE libSceSaveData.native)
@ -177,6 +375,11 @@ if(BUILD_TESTING)
endif()
add_test(NAME host_thread_local COMMAND host_thread_local_tests)
set_tests_properties(host_thread_local PROPERTIES TIMEOUT 15)
if(MINGW)
add_test(NAME prx_thread_local_destructors COMMAND ${CMAKE_COMMAND} -DNM=${CMAKE_NM} -DOBJDUMP=${CMAKE_OBJDUMP}
-DMODULES=$<TARGET_FILE_DIR:libc> -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/ThreadLocalDestructors.cmake)
set_tests_properties(prx_thread_local_destructors PROPERTIES TIMEOUT 300)
endif()
add_test_executable(savedata_core_write_replacement_tests tests/SaveDataWriteReplacement.cpp)
target_include_directories(savedata_core_write_replacement_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@ -196,6 +399,16 @@ if(BUILD_TESTING)
configure_windows_unwind(savedata_replace_file_failure_tests)
add_test(NAME savedata_replace_file_failure COMMAND savedata_replace_file_failure_tests)
add_test_executable(guest_crt_tests tests/GuestCrt.cpp)
target_include_directories(guest_crt_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_crt_tests PRIVATE libSceAmpr libc)
configure_windows_unwind(guest_crt_tests)
add_test(NAME guest_crt COMMAND guest_crt_tests)
if(WIN32)
set_tests_properties(guest_crt PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAmpr>")
endif()
if(MINGW)
target_compile_options(savedata_core_write_replacement_tests PRIVATE -fasynchronous-unwind-tables)
target_compile_options(savedata_native_write_replacement_tests PRIVATE -fasynchronous-unwind-tables)
@ -207,4 +420,44 @@ if(BUILD_TESTING)
set_tests_properties(savedata_native_write_replacement PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSaveData.native>")
endif()
add_test_executable(guest_ppsa01530_exports_tests tests/GuestPPSA01530Exports.cpp)
target_include_directories(guest_ppsa01530_exports_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_ppsa01530_exports_tests PRIVATE libkernel libSceJson2 libSceNet libScePad libc)
configure_windows_unwind(guest_ppsa01530_exports_tests)
add_test(NAME guest_ppsa01530_exports COMMAND guest_ppsa01530_exports_tests)
if(WIN32)
set_tests_properties(guest_ppsa01530_exports PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_posix_random_tests tests/GuestPosixRandom.cpp)
target_include_directories(guest_posix_random_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_posix_random_tests PRIVATE libScePosixForWebKit)
configure_windows_unwind(guest_posix_random_tests)
add_test(NAME guest_posix_random COMMAND guest_posix_random_tests)
if(WIN32)
set_tests_properties(guest_posix_random PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libScePosixForWebKit>")
endif()
add_test_executable(MemoryPoolTest
tests/MemoryPoolTest.cpp
prx/libkernel/DirectMemory/MemoryPool.cpp
)
target_include_directories(MemoryPoolTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(MINGW)
target_compile_options(MemoryPoolTest PRIVATE -fasynchronous-unwind-tables)
endif()
add_test(NAME MemoryPoolTest COMMAND MemoryPoolTest)
add_test_executable(guest_acm_tests tests/GuestAcm.cpp)
target_include_directories(guest_acm_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_acm_tests PRIVATE libSceAcm libc)
configure_windows_unwind(guest_acm_tests)
add_test(NAME guest_acm COMMAND guest_acm_tests)
if(WIN32)
set_tests_properties(guest_acm PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAcm>")
endif()
endif()

View File

@ -16,6 +16,23 @@ struct alignas(16) __m128 { float v[4]; };
using Bool = std::uint8_t;
struct SonyLconv {
char* monetary[7];
char chars[14];
char pad[2];
char* decimal_point;
char* grouping;
char* thousands_sep;
char* frac_grouping;
char* frac_sep;
char* false_text;
char* true_text;
char* no_text;
char* yes_text;
};
static_assert(offsetof(SonyLconv, decimal_point) == 0x48);
static_assert(sizeof(SonyLconv) == 0x90);
using KernelModule = std::int32_t;
using KernelCpumask = std::uint64_t;
using KernelUseconds = unsigned int;
@ -78,6 +95,14 @@ struct KernelAioRwRequest {
std::int32_t fd;
};
struct KernelAioSchedulingParam {
std::int32_t schedulingWindowSize;
std::int32_t delayedCountLimit;
std::uint32_t enableSplit;
std::uint32_t splitSize;
std::uint32_t splitChunkSize;
};
struct KernelBatchMapEntry {
void* start;
std::uint64_t offset;
@ -205,6 +230,19 @@ struct ModuleSegmentInfo {
std::int32_t prot;
};
struct ModuleInfo {
std::uint64_t st_size;
char name[256];
ModuleSegmentInfo segments[4];
std::uint32_t segment_count;
std::uint8_t fingerprint[20];
};
static_assert(offsetof(ModuleInfo, name) == 0x8);
static_assert(offsetof(ModuleInfo, segments) == 0x108);
static_assert(offsetof(ModuleInfo, segment_count) == 0x148);
static_assert(offsetof(ModuleInfo, fingerprint) == 0x14C);
static_assert(sizeof(ModuleInfo) == 0x160);
struct ModuleInfoEx {
std::uint64_t st_size;
char name[256];
@ -242,6 +280,12 @@ struct ModuleInfoForUnwind {
std::uint64_t seg0_size;
};
struct InternalSegmentInfo {
std::uint64_t address;
std::uint64_t size;
};
static_assert(sizeof(InternalSegmentInfo) == 0x10);
struct MallocReplace {
std::uint64_t size = sizeof(MallocReplace);
void* malloc_initialize = nullptr;
@ -534,6 +578,13 @@ struct Audio3dOpenParameters {
std::uint32_t num_beds;
};
struct Audio3dAttribute {
std::uint32_t attribute_id;
std::uint32_t pad;
const void* value;
std::uint64_t value_size;
};
using AudioPropagationHandle = std::uint64_t;
struct AudioPropagationStructDescriptor {
@ -1214,13 +1265,21 @@ struct NetCtlNatInfo { std::uint8_t opaque[128]; };
union NetCtlInfo { std::uint8_t opaque[256]; };
struct NetCtlIfStat {
std::uint32_t device;
std::uint64_t tx_bytes;
std::uint64_t rx_bytes;
std::uint32_t reserved[8];
};
using NetCtlCallback = void (*)(int, void*);
struct HttpEpoll {};
struct HttpEpoll;
using HttpEpollHandle = HttpEpoll*;
using HttpsCallback = int (*)(int, unsigned int, void* const*, int, void*);
using HttpRedirectCallback = int (*)(int, std::int32_t, std::int32_t*, const char*, void*);
using HttpCookieRecvCallback = int (*)(int, const char*, const char*, std::uint64_t, void*);
using HttpAuthInfoCallback = int (*)(int, int, const char*, char*, char*, int, std::uint8_t**, std::uint64_t*, int*, void*);
struct HttpNBEvent { std::uint8_t opaque[64]; };
@ -1257,6 +1316,18 @@ struct NpTitleId { char data[13]; char pad[3]; };
struct NpTitleSecret { std::uint8_t data[128]; };
struct NpContentRestriction { std::uint8_t opaque[128]; };
struct NpOnlineId { char data[17]; char pad[3]; };
struct SharePlayConnectionInfoA {
std::int32_t status;
std::int32_t mode;
NpOnlineId hostOnlineId;
NpOnlineId visitorOnlineId;
std::uint64_t hostAccountId;
std::uint64_t visitorAccountId;
std::int32_t hostUserId;
std::int32_t visitorUserId;
};
static_assert(sizeof(SharePlayConnectionInfoA) == 72 && offsetof(SharePlayConnectionInfoA, hostAccountId) == 48 && offsetof(SharePlayConnectionInfoA, hostUserId) == 64);
struct NpId { NpOnlineId online_id; std::uint8_t opaque[4]; };
struct NpCreateAsyncRequestParameter { std::uint8_t opaque[64]; };
struct NpCheckPremiumParameter { std::uint8_t opaque[64]; };
@ -1390,7 +1461,12 @@ struct SaveDataMountInfo {
struct SceSaveDataTitleId { char data[10]; char pad[2]; };
struct SceSaveDataDirName { char data[32]; };
struct SaveDataSearchInfo { std::uint8_t opaque[128]; };
struct SaveDataSearchInfo {
std::uint64_t blocks;
std::uint64_t free_blocks;
std::uint8_t reserved[32];
};
static_assert(sizeof(SaveDataSearchInfo) == 48);
struct SaveDataMemoryData { void* buf; std::size_t buf_size; std::size_t offset; };
struct SaveDataMount3 {
@ -1513,6 +1589,13 @@ struct SaveDataBackup {
std::uint8_t reserved[32];
};
struct SaveDataConvert {
std::int32_t user_id;
std::int32_t pad;
const SceSaveDataDirName* dir_name;
std::uint8_t unknown[48];
};
struct AppContentInitParam { char reserved[32]; };
struct AppContentBootParam {
@ -1532,8 +1615,50 @@ struct ContentExportInitParam2 {
std::int64_t reserved1;
};
struct ContentExportParam {
char title[257];
char comment[257];
char content_type[65];
};
static_assert(sizeof(ContentExportParam) == 579);
struct ContentExportCallbackParam {
std::size_t content_length;
void* func;
void* user_data;
};
struct ContentSearchInitParam { std::size_t memory_size; };
struct ContentSearchColumnValue {
std::uint32_t size;
std::int64_t value;
};
struct ContentSearchContentColumn {
std::int32_t column_type;
std::int32_t column_operator;
const ContentSearchColumnValue* value;
std::int32_t logical_connector;
};
struct ContentSearchContentColumnSet {
const ContentSearchContentColumn* columns;
std::int32_t columns_length;
std::int32_t logical_connector;
};
struct ContentSearchContentOrderByCondition {
std::int32_t column_type;
std::int32_t sort_type;
};
static_assert(sizeof(ContentSearchColumnValue) == 16);
static_assert(sizeof(ContentSearchContentColumn) == 24);
static_assert(offsetof(ContentSearchContentColumn, logical_connector) == 16);
static_assert(sizeof(ContentSearchContentColumnSet) == 16);
static_assert(sizeof(ContentSearchContentOrderByCondition) == 8);
struct PngEncCreateParam {
std::uint32_t this_size;
std::uint32_t attribute;
@ -1826,6 +1951,19 @@ struct VideoOutOutputStatus {
std::uint64_t reserved[3] = {};
};
struct VideoOutResolutionStatus {
std::uint32_t fullWidth = 0;
std::uint32_t fullHeight = 0;
std::uint32_t paneWidth = 0;
std::uint32_t paneHeight = 0;
std::uint64_t refreshRate = 0;
float screenSizeInInch = 0.0f;
std::uint16_t flags = 0;
std::uint16_t reserved0 = 0;
std::uint32_t reserved1[3] = {};
};
static_assert(sizeof(VideoOutResolutionStatus) == 48 && offsetof(VideoOutResolutionStatus, refreshRate) == 16 && offsetof(VideoOutResolutionStatus, screenSizeInInch) == 24);
struct VideoOutOutputOptions { std::uint32_t internalData[16] = {}; };
struct VideoOutColorSettings {

View File

@ -0,0 +1,30 @@
#ifndef CORE_LIBS_NID_MACHONIDPATCHER_HPP
#define CORE_LIBS_NID_MACHONIDPATCHER_HPP
#include <nid/IBinaryPatcher.hpp>
#include <cstdint>
#include <string>
#include <vector>
namespace Nid {
constexpr std::uint32_t kMachOMagic64 = 0xfeedfacfu;
struct MachOExport {
std::string Name;
std::uint64_t Flags = 0;
std::uint64_t Address = 0;
std::uint64_t Other = 0;
std::string ImportName;
};
std::vector<MachOExport> ReadMachOExports(const std::vector<std::uint8_t>& binary);
class MachONidPatcher final : public IBinaryPatcher {
public:
void PatchNids(std::vector<std::uint8_t>& binary, const std::string& libraryName, const std::unordered_set<std::string>& excludedExports) const override;
};
}
#endif

View File

@ -0,0 +1,15 @@
#ifndef NID_NATIVEPATH_HPP
#define NID_NATIVEPATH_HPP
#include <filesystem>
#include <string>
namespace Nid::Internal {
inline std::filesystem::path NativePath(const std::string& path) {
return std::filesystem::path(std::u8string(path.begin(), path.end()));
}
}
#endif

View File

@ -61,7 +61,7 @@ inline std::string StripNidPostfix(const std::string& name) {
template<typename T>
T Read(const std::vector<std::uint8_t>& buf, std::size_t offset) {
if (offset + sizeof(T) > buf.size()) throw std::runtime_error("read out of bounds");
if (offset > buf.size() || sizeof(T) > buf.size() - offset) throw std::runtime_error("read out of bounds");
T v;
std::memcpy(&v, buf.data() + offset, sizeof(T));
return v;
@ -69,7 +69,7 @@ T Read(const std::vector<std::uint8_t>& buf, std::size_t offset) {
template<typename T>
void Write(std::vector<std::uint8_t>& buf, std::size_t offset, const T& v) {
if (offset + sizeof(T) > buf.size()) throw std::runtime_error("write out of bounds");
if (offset > buf.size() || sizeof(T) > buf.size() - offset) throw std::runtime_error("write out of bounds");
std::memcpy(buf.data() + offset, &v, sizeof(T));
}
@ -78,6 +78,7 @@ inline std::string ReadCStr(const std::vector<std::uint8_t>& buf, std::size_t of
std::string s;
while (offset < buf.size() && buf[offset] != 0u)
s.push_back(static_cast<char>(buf[offset++]));
if (offset == buf.size()) throw std::runtime_error("unterminated cstr");
return s;
}

View File

@ -1,5 +1,6 @@
#include <nid/BinaryPatcherFactory.hpp>
#include <nid/ElfPatcher.hpp>
#include <nid/MachONidPatcher.hpp>
#include <nid/PeNidPatcher.hpp>
#include <stdexcept>
@ -10,6 +11,8 @@ std::unique_ptr<IBinaryPatcher> MakePatcher(const std::vector<std::uint8_t>& bin
return std::make_unique<ElfNidPatcher>();
if (binary.size() >= 2 && binary[0] == 'M' && binary[1] == 'Z')
return std::make_unique<PeNidPatcher>();
if (binary.size() >= 4 && binary[0] == 0xcf && binary[1] == 0xfa && binary[2] == 0xed && binary[3] == 0xfe)
return std::make_unique<MachONidPatcher>();
throw std::runtime_error("unrecognized binary format");
}

View File

@ -15,6 +15,11 @@ namespace Nid {
namespace {
void RequireElfRange(const std::vector<std::uint8_t>& elf, std::uint64_t offset, std::uint64_t size, const char* table) {
if (offset > elf.size() || size > elf.size() - offset)
throw std::runtime_error(std::string("invalid ELF ") + table + " range");
}
std::uint32_t GnuHash(const std::string& name) {
std::uint32_t h = 5381u;
for (const unsigned char c : name)
@ -36,6 +41,18 @@ GnuHashLayout ReadGnuHashLayout(const std::vector<std::uint8_t>& elf, std::size_
return layout;
}
void ValidateGnuHash(const std::vector<std::uint8_t>& elf, std::size_t offset, std::size_t size, std::size_t symCount) {
if (offset > elf.size() || size > elf.size() - offset || size < 16u)
throw std::runtime_error("invalid gnu.hash section range");
const auto layout = ReadGnuHashLayout(elf, offset);
if (layout.SymOffset > symCount || !layout.BloomSize || (layout.BloomSize & (layout.BloomSize - 1u)) ||
layout.BloomShift >= 32u || (!layout.NBuckets && layout.SymOffset != symCount))
throw std::runtime_error("invalid gnu.hash geometry");
const std::uint64_t required = 16u + std::uint64_t{layout.BloomSize} * 8u +
std::uint64_t{layout.NBuckets} * 4u + (symCount - layout.SymOffset) * 4u;
if (required > size) throw std::runtime_error("gnu.hash section too small to rebuild in place");
}
void ReorderDynSymForGnuHash(
std::vector<std::uint8_t>& elf,
std::size_t dynSymOffset,
@ -204,49 +221,65 @@ void RemapDynamicNeededOffsets(
}
}
struct VersionNameField {
std::size_t Offset;
std::uint32_t Name;
};
std::vector<VersionNameField> ReadVersionNameFields(const std::vector<std::uint8_t>& elf, const Elf64_Ehdr& ehdr) {
using namespace Internal;
std::vector<VersionNameField> fields;
for (std::uint16_t i = 0u; i < ehdr.e_shnum; ++i) {
const auto section = Read<Elf64_Shdr>(elf, static_cast<std::size_t>(ehdr.e_shoff) + i * sizeof(Elf64_Shdr));
if (section.sh_type != kShtGnuVerneed || section.sh_size == 0u) continue;
if (section.sh_offset > elf.size() || section.sh_size > elf.size() - section.sh_offset)
throw std::runtime_error("invalid .gnu.version_r section range");
const auto location = [&](std::uint64_t relative, std::size_t size) {
if (relative > section.sh_size || size > section.sh_size - relative)
throw std::runtime_error(".gnu.version_r record outside section");
return static_cast<std::size_t>(section.sh_offset + relative);
};
const auto advance = [&](std::uint64_t current, std::uint32_t step, std::size_t size) {
if (step < size || step > section.sh_size - current)
throw std::runtime_error("invalid .gnu.version_r record link");
return current + step;
};
std::uint64_t current = 0u;
while (true) {
const auto offset = location(current, sizeof(Elf64_Verneed));
const auto need = Read<Elf64_Verneed>(elf, offset);
if (need.vn_version != 1u) throw std::runtime_error("unsupported .gnu.version_r structure version");
fields.push_back({offset + offsetof(Elf64_Verneed, vn_file), need.vn_file});
if (need.vn_cnt != 0u) {
auto auxiliary = advance(current, need.vn_aux, sizeof(Elf64_Verneed));
for (std::uint16_t index = 0u; index < need.vn_cnt; ++index) {
const auto auxOffset = location(auxiliary, sizeof(Elf64_Vernaux));
const auto aux = Read<Elf64_Vernaux>(elf, auxOffset);
fields.push_back({auxOffset + offsetof(Elf64_Vernaux, vna_name), aux.vna_name});
if (index + 1u == need.vn_cnt) {
if (aux.vna_next != 0u) throw std::runtime_error(".gnu.version_r auxiliary count mismatch");
} else {
auxiliary = advance(auxiliary, aux.vna_next, sizeof(Elf64_Vernaux));
}
}
}
if (need.vn_next == 0u) break;
current = advance(current, need.vn_next, sizeof(Elf64_Verneed));
}
}
return fields;
}
void RemapVerneedOffsets(
std::vector<std::uint8_t>& elf,
const Elf64_Ehdr& ehdr,
const std::vector<std::pair<std::uint32_t, std::uint32_t>>& oldToNewOffset
) {
using namespace Internal;
for (std::uint16_t i = 0u; i < ehdr.e_shnum; ++i) {
const std::size_t shOffset = static_cast<std::size_t>(ehdr.e_shoff) + i * sizeof(Elf64_Shdr);
const auto shdr = Read<Elf64_Shdr>(elf, shOffset);
if (shdr.sh_type != kShtGnuVerneed) continue;
const std::size_t verneedOffset = static_cast<std::size_t>(shdr.sh_offset);
std::size_t entryOffset = verneedOffset;
while (true) {
const auto verneed = Read<Elf64_Verneed>(elf, entryOffset);
const auto mappedFile = std::find_if(
oldToNewOffset.begin(), oldToNewOffset.end(),
[&](const auto& entry) { return entry.first == verneed.vn_file; }
);
if (mappedFile != oldToNewOffset.end())
Write(elf, entryOffset + offsetof(Elf64_Verneed, vn_file), mappedFile->second);
std::size_t auxOffset = entryOffset + verneed.vn_aux;
for (std::uint16_t a = 0u; a < verneed.vn_cnt; ++a) {
const auto vernaux = Read<Elf64_Vernaux>(elf, auxOffset);
const auto mappedName = std::find_if(
oldToNewOffset.begin(), oldToNewOffset.end(),
[&](const auto& entry) { return entry.first == vernaux.vna_name; }
);
if (mappedName != oldToNewOffset.end())
Write(elf, auxOffset + offsetof(Elf64_Vernaux, vna_name), mappedName->second);
if (vernaux.vna_next == 0u) break;
auxOffset += vernaux.vna_next;
}
if (verneed.vn_next == 0u) break;
entryOffset += verneed.vn_next;
}
for (const auto& field : ReadVersionNameFields(elf, ehdr)) {
const auto mapped = std::find_if(oldToNewOffset.begin(), oldToNewOffset.end(),
[&](const auto& entry) { return entry.first == field.Name; });
if (mapped != oldToNewOffset.end()) Write(elf, field.Offset, mapped->second);
}
}
@ -275,35 +308,8 @@ std::vector<std::uint32_t> CollectDynamicNameOffsets(const std::vector<std::uint
}
std::vector<std::uint32_t> CollectVerneedNameOffsets(const std::vector<std::uint8_t>& elf, const Elf64_Ehdr& ehdr) {
using namespace Internal;
std::vector<std::uint32_t> offsets;
for (std::uint16_t i = 0u; i < ehdr.e_shnum; ++i) {
const std::size_t shOffset = static_cast<std::size_t>(ehdr.e_shoff) + i * sizeof(Elf64_Shdr);
const auto shdr = Read<Elf64_Shdr>(elf, shOffset);
if (shdr.sh_type != kShtGnuVerneed) continue;
std::size_t entryOffset = static_cast<std::size_t>(shdr.sh_offset);
while (true) {
const auto verneed = Read<Elf64_Verneed>(elf, entryOffset);
offsets.push_back(verneed.vn_file);
std::size_t auxOffset = entryOffset + verneed.vn_aux;
for (std::uint16_t a = 0u; a < verneed.vn_cnt; ++a) {
const auto vernaux = Read<Elf64_Vernaux>(elf, auxOffset);
offsets.push_back(vernaux.vna_name);
if (vernaux.vna_next == 0u) break;
auxOffset += vernaux.vna_next;
}
if (verneed.vn_next == 0u) break;
entryOffset += verneed.vn_next;
}
}
for (const auto& field : ReadVersionNameFields(elf, ehdr)) offsets.push_back(field.Name);
return offsets;
}
@ -316,6 +322,9 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
if (elf[4] != 2) throw std::runtime_error("not ELF64");
const auto ehdr = Read<Elf64_Ehdr>(elf, 0u);
if (ehdr.e_ident[5] != 1 || ehdr.e_shentsize != sizeof(Elf64_Shdr))
throw std::runtime_error("unsupported ELF byte order or section header size");
RequireElfRange(elf, ehdr.e_shoff, std::uint64_t{ehdr.e_shnum} * sizeof(Elf64_Shdr), "section table");
std::size_t dynSymOffset = 0u, dynSymSize = 0u;
std::size_t gnuHashOffset = 0u, gnuHashSize = 0u;
@ -326,6 +335,9 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
const std::size_t shOffset = static_cast<std::size_t>(ehdr.e_shoff) + i * sizeof(Elf64_Shdr);
const auto shdr = Read<Elf64_Shdr>(elf, shOffset);
if (shdr.sh_type == kShtDynsym) {
if (shdr.sh_entsize != sizeof(Elf64_Sym) || shdr.sh_size % sizeof(Elf64_Sym) || shdr.sh_link >= ehdr.e_shnum)
throw std::runtime_error("invalid ELF dynsym layout");
RequireElfRange(elf, shdr.sh_offset, shdr.sh_size, "dynsym");
dynSymOffset = static_cast<std::size_t>(shdr.sh_offset);
dynSymSize = static_cast<std::size_t>(shdr.sh_size);
dynSymSectionIndex = i;
@ -333,7 +345,6 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
if (shdr.sh_type == kShtGnuHash) {
gnuHashOffset = static_cast<std::size_t>(shdr.sh_offset);
gnuHashSize = static_cast<std::size_t>(shdr.sh_size);
gnuHashSymOffset = Read<std::uint32_t>(elf, gnuHashOffset + 4u);
}
if (shdr.sh_type == kShtGnuVersym)
versymOffset = static_cast<std::size_t>(shdr.sh_offset);
@ -345,6 +356,10 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
const std::size_t symCount = dynSymSize / sizeof(Elf64_Sym);
if (symCount == 0u) throw std::runtime_error(".dynsym is empty");
if (gnuHashOffset != 0u) {
ValidateGnuHash(elf, gnuHashOffset, gnuHashSize, symCount);
gnuHashSymOffset = Read<std::uint32_t>(elf, gnuHashOffset + 4u);
}
const std::size_t dynStrSectionLink = [&]() -> std::size_t {
for (std::uint16_t i = 0u; i < ehdr.e_shnum; ++i) {
@ -359,6 +374,8 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
{
const std::size_t shOffset = static_cast<std::size_t>(ehdr.e_shoff) + dynStrSectionLink * sizeof(Elf64_Shdr);
const auto shdr = Read<Elf64_Shdr>(elf, shOffset);
if (shdr.sh_type != 3) throw std::runtime_error("invalid ELF dynstr section type");
RequireElfRange(elf, shdr.sh_offset, shdr.sh_size, "dynstr");
dynStrOffset = static_cast<std::size_t>(shdr.sh_offset);
dynStrSize = static_cast<std::size_t>(shdr.sh_size);
}
@ -427,7 +444,7 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
const auto addName = [&](std::uint32_t oldOffset, std::string value) {
const auto existing = std::find_if(
names.begin(), names.end(),
[&](const auto& entry) { return entry.first == oldOffset; }
[&](const auto& entry) { return entry.first == oldOffset && entry.second == value; }
);
if (existing == names.end()) names.emplace_back(oldOffset, std::move(value));
};
@ -463,8 +480,9 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
newDynStr.push_back(0u);
}
std::vector<std::pair<std::uint32_t, std::uint32_t>> oldToNewOffset;
for (const auto& name : names) oldToNewOffset.emplace_back(name.first, valueOffsets.at(name.second));
std::vector<std::pair<std::uint32_t, std::uint32_t>> preservedToNewOffset;
for (const auto offset : preservedOffsets)
preservedToNewOffset.emplace_back(offset, valueOffsets.at(ReadCStr(origDynStr, offset)));
if (newDynStr.size() > dynStrSize) {
throw std::runtime_error(
@ -475,25 +493,15 @@ void ElfNidPatcher::PatchNids(std::vector<std::uint8_t>& elf, const std::string&
newDynStr.resize(dynStrSize, 0u);
std::vector<std::string> newSymbolNames(symCount);
for (std::size_t i = 1u; i < symCount; ++i) {
const std::size_t symOffset = dynSymOffset + i * sizeof(Elf64_Sym);
const auto sym = Read<Elf64_Sym>(elf, symOffset);
if (sym.st_name == 0u) continue;
const auto mapped = std::find_if(
oldToNewOffset.begin(), oldToNewOffset.end(),
[&](const auto& entry) { return entry.first == sym.st_name; }
);
if (mapped == oldToNewOffset.end()) continue;
newSymbolNames[i] = ReadCStr(newDynStr, mapped->second);
Write(elf, symOffset + offsetof(Elf64_Sym, st_name), mapped->second);
for (const auto& use : uses) {
newSymbolNames[use.symIndex] = use.newValue;
Write(elf, dynSymOffset + use.symIndex * sizeof(Elf64_Sym) + offsetof(Elf64_Sym, st_name), valueOffsets.at(use.newValue));
}
std::memcpy(elf.data() + dynStrOffset, newDynStr.data(), newDynStr.size());
RemapDynamicNeededOffsets(elf, ehdr, oldToNewOffset);
RemapVerneedOffsets(elf, ehdr, oldToNewOffset);
RemapDynamicNeededOffsets(elf, ehdr, preservedToNewOffset);
RemapVerneedOffsets(elf, ehdr, preservedToNewOffset);
if (gnuHashOffset != 0u) {
const auto bucketCount = Read<std::uint32_t>(elf, gnuHashOffset);

View File

@ -1,7 +1,9 @@
#include <nid/ExportExclusions.hpp>
#include <nid/ElfPatcher.hpp>
#include <nid/PeNidPatcher.hpp>
#include <nid/MachONidPatcher.hpp>
#include <nid/NidPatcherUtils.hpp>
#include <nid/NativePath.hpp>
#include <bit>
#include <cstring>
#include <fstream>
@ -48,7 +50,12 @@ std::unordered_set<std::string> ReadPeExports(const std::vector<std::uint8_t>& b
if (!directory.VirtualAddress || directory.Size < sizeof(PeExportDirectory)) throw std::runtime_error("missing reference PE exports");
const auto sections = optional + optionalSize;
RequireRange(binary, sections, std::uint64_t{sectionCount} * sizeof(PeSectionHeader));
const auto headersSize = ReadValue<std::uint32_t>(binary, optional + 60);
const auto mapRva = [&](std::uint32_t rva, std::uint64_t size) -> std::uint64_t {
if (rva < headersSize && size <= headersSize - rva) {
RequireRange(binary, rva, size);
return rva;
}
for (std::uint16_t index = 0; index < sectionCount; ++index) {
const auto section = ReadValue<PeSectionHeader>(binary, sections + std::uint64_t{index} * sizeof(PeSectionHeader));
if (rva < section.VirtualAddress) continue;
@ -63,14 +70,20 @@ std::unordered_set<std::string> ReadPeExports(const std::vector<std::uint8_t>& b
const auto table = ReadValue<PeExportDirectory>(binary, mapRva(directory.VirtualAddress, sizeof(PeExportDirectory)));
if (!table.NumberOfNames) throw std::runtime_error("reference PE has no named exports");
const auto names = mapRva(table.AddressOfNames, std::uint64_t{table.NumberOfNames} * 4);
const auto ordinals = mapRva(table.AddressOfNameOrdinals, std::uint64_t{table.NumberOfNames} * 2);
const auto functions = mapRva(table.AddressOfFunctions, std::uint64_t{table.NumberOfFunctions} * 4);
std::unordered_set<std::string> result;
for (std::uint32_t index = 0; index < table.NumberOfNames; ++index) {
const auto ordinal = ReadValue<std::uint16_t>(binary, ordinals + std::uint64_t{index} * 2);
if (ordinal >= table.NumberOfFunctions) throw std::runtime_error("invalid reference PE export ordinal");
if (!ReadValue<std::uint32_t>(binary, functions + std::uint64_t{ordinal} * 4)) continue;
const auto rva = ReadValue<std::uint32_t>(binary, names + std::uint64_t{index} * 4);
const auto offset = mapRva(rva, 1);
auto name = ReadName(binary, offset, binary.size() - offset);
mapRva(rva, name.size() + 1);
if (!result.insert(name).second) throw std::runtime_error("duplicate reference export: " + name);
}
if (result.empty()) throw std::runtime_error("reference PE has no named exports");
return result;
}
@ -109,7 +122,7 @@ std::string NormalizeExportName(const std::string& name) {
std::unordered_set<std::string> ReadExportExclusions(const std::string& path) {
if constexpr (std::endian::native != std::endian::little) throw std::runtime_error("export references require a little-endian host");
std::ifstream input(path, std::ios::binary | std::ios::ate);
std::ifstream input(Internal::NativePath(path), std::ios::binary | std::ios::ate);
if (!input) throw std::runtime_error("cannot open export reference: " + path);
const auto size = input.tellg();
if (size <= 0) throw std::runtime_error("empty or unreadable export reference: " + path);
@ -121,6 +134,12 @@ std::unordered_set<std::string> ReadExportExclusions(const std::string& path) {
exports = ReadPeExports(binary);
} else if (binary.size() >= 4 && binary[0] == 0x7f && binary[1] == 'E' && binary[2] == 'L' && binary[3] == 'F') {
exports = ReadElfExports(binary);
} else if (binary.size() >= 4 && binary[0] == 0xcf && binary[1] == 0xfa && binary[2] == 0xed && binary[3] == 0xfe) {
for (const auto& entry : ReadMachOExports(binary)) {
if (entry.Name.size() < 2 || entry.Name[0] != '_') throw std::runtime_error("invalid reference Mach-O export: " + entry.Name);
if (!exports.insert(entry.Name.substr(1)).second) throw std::runtime_error("duplicate reference export: " + entry.Name);
}
if (exports.empty()) throw std::runtime_error("reference Mach-O has no exports");
} else {
throw std::runtime_error("unrecognized export reference format: " + path);
}

View File

@ -0,0 +1,493 @@
#include <nid/MachONidPatcher.hpp>
#include <nid/NidResolver.hpp>
#include <nid/NidPatcherUtils.hpp>
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <cstring>
#include <memory>
#include <optional>
#include <set>
#include <stdexcept>
#include <string_view>
#include <unordered_map>
namespace Nid {
namespace {
using Internal::Read;
using Internal::Write;
constexpr std::uint32_t kLcSegment64 = 0x19;
constexpr std::uint32_t kLcCodeSignature = 0x1d;
constexpr std::uint32_t kLcDyldInfo = 0x22;
constexpr std::uint32_t kLcDyldInfoOnly = 0x80000022u;
constexpr std::uint32_t kLcDyldExportsTrie = 0x80000033u;
constexpr std::uint32_t kLcDyldChainedFixups = 0x80000034u;
constexpr std::uint32_t kLcLoadDylib = 0x0c;
constexpr std::uint32_t kLcLoadWeakDylib = 0x80000018u;
constexpr std::uint32_t kLcReexportDylib = 0x8000001fu;
constexpr std::uint32_t kLcLazyLoadDylib = 0x20;
constexpr std::uint32_t kLcLoadUpwardDylib = 0x80000023u;
constexpr std::uint64_t kExportWeakDefinition = 0x04;
constexpr std::uint64_t kExportReexport = 0x08;
constexpr std::uint64_t kExportStubAndResolver = 0x10;
constexpr std::uint32_t kImportFormatPlain = 1;
constexpr std::uint32_t kImportFormatAddend = 2;
constexpr std::uint32_t kImportFormatAddend64 = 3;
constexpr std::uint64_t kPageSize = 0x1000;
struct MachHeader64 {
std::uint32_t Magic;
std::uint32_t CpuType;
std::uint32_t CpuSubtype;
std::uint32_t FileType;
std::uint32_t CommandCount;
std::uint32_t CommandBytes;
std::uint32_t Flags;
std::uint32_t Reserved;
};
struct LoadCommand {
std::uint32_t Cmd;
std::uint32_t Size;
};
struct SegmentCommand64 {
std::uint32_t Cmd;
std::uint32_t Size;
char Name[16];
std::uint64_t VmAddress;
std::uint64_t VmSize;
std::uint64_t FileOffset;
std::uint64_t FileSize;
std::uint32_t MaxProtection;
std::uint32_t InitProtection;
std::uint32_t SectionCount;
std::uint32_t Flags;
};
struct LinkeditDataCommand {
std::uint32_t Cmd;
std::uint32_t Size;
std::uint32_t DataOffset;
std::uint32_t DataSize;
};
struct DyldInfoCommand {
std::uint32_t Cmd;
std::uint32_t Size;
std::uint32_t RebaseOffset;
std::uint32_t RebaseSize;
std::uint32_t BindOffset;
std::uint32_t BindSize;
std::uint32_t WeakBindOffset;
std::uint32_t WeakBindSize;
std::uint32_t LazyBindOffset;
std::uint32_t LazyBindSize;
std::uint32_t ExportOffset;
std::uint32_t ExportSize;
};
struct ChainedFixupsHeader {
std::uint32_t Version;
std::uint32_t StartsOffset;
std::uint32_t ImportsOffset;
std::uint32_t SymbolsOffset;
std::uint32_t ImportsCount;
std::uint32_t ImportsFormat;
std::uint32_t SymbolsFormat;
};
void RequireRange(const std::vector<std::uint8_t>& binary, std::uint64_t offset, std::uint64_t size) {
if (offset > binary.size() || size > binary.size() - offset) throw std::runtime_error("Mach-O range out of bounds");
}
std::uint64_t ReadUleb(const std::vector<std::uint8_t>& data, std::size_t& cursor, std::size_t end) {
std::uint64_t value = 0;
unsigned shift = 0;
for (;;) {
if (cursor >= end) throw std::runtime_error("truncated uleb128 in export trie");
const auto byte = data[cursor++];
if (shift >= 64 || (shift == 63 && (byte & 0x7e) != 0)) throw std::runtime_error("uleb128 overflow in export trie");
value |= std::uint64_t{byte & 0x7fu} << shift;
if ((byte & 0x80) == 0) return value;
shift += 7;
}
}
void WriteUleb(std::vector<std::uint8_t>& out, std::uint64_t value) {
do {
std::uint8_t byte = value & 0x7f;
value >>= 7;
if (value != 0) byte |= 0x80;
out.push_back(byte);
} while (value != 0);
}
std::size_t UlebSize(std::uint64_t value) {
std::size_t size = 1;
while (value >>= 7) ++size;
return size;
}
std::string ReadTrieString(const std::vector<std::uint8_t>& data, std::size_t& cursor, std::size_t end) {
const auto start = cursor;
while (cursor < end && data[cursor] != 0) ++cursor;
if (cursor >= end) throw std::runtime_error("unterminated string in export trie");
std::string text(reinterpret_cast<const char*>(data.data() + start), cursor - start);
++cursor;
return text;
}
struct Image {
MachHeader64 Header {};
std::vector<std::size_t> Commands;
};
Image ParseImage(const std::vector<std::uint8_t>& binary) {
Image image;
image.Header = Read<MachHeader64>(binary, 0);
if (image.Header.Magic != kMachOMagic64) throw std::runtime_error("not a 64-bit little-endian Mach-O image");
RequireRange(binary, sizeof(MachHeader64), image.Header.CommandBytes);
std::size_t cursor = sizeof(MachHeader64);
const auto end = cursor + image.Header.CommandBytes;
for (std::uint32_t index = 0; index < image.Header.CommandCount; ++index) {
if (cursor + sizeof(LoadCommand) > end) throw std::runtime_error("load command out of bounds");
const auto command = Read<LoadCommand>(binary, cursor);
if (command.Size < sizeof(LoadCommand) || command.Size % 8 != 0 || command.Size > end - cursor) throw std::runtime_error("invalid load command size");
image.Commands.push_back(cursor);
cursor += command.Size;
}
return image;
}
struct TrieLocation {
std::size_t OffsetField;
std::size_t SizeField;
};
std::optional<TrieLocation> FindTrie(const std::vector<std::uint8_t>& binary, const Image& image) {
std::optional<TrieLocation> found;
for (const auto offset : image.Commands) {
const auto cmd = Read<LoadCommand>(binary, offset).Cmd;
std::optional<TrieLocation> here;
if (cmd == kLcDyldExportsTrie) here = TrieLocation{offset + offsetof(LinkeditDataCommand, DataOffset), offset + offsetof(LinkeditDataCommand, DataSize)};
else if (cmd == kLcDyldInfo || cmd == kLcDyldInfoOnly) {
if (Read<DyldInfoCommand>(binary, offset).ExportSize != 0)
here = TrieLocation{offset + offsetof(DyldInfoCommand, ExportOffset), offset + offsetof(DyldInfoCommand, ExportSize)};
}
if (!here) continue;
if (found) throw std::runtime_error("Mach-O image has more than one export trie");
found = here;
}
return found;
}
void ParseTrieNode(const std::vector<std::uint8_t>& data, std::size_t start, std::size_t end, std::size_t node, std::string& prefix, std::set<std::size_t>& visited, std::vector<MachOExport>& out) {
if (node >= end - start) throw std::runtime_error("export trie node out of bounds");
if (!visited.insert(node).second) throw std::runtime_error("export trie has a cycle");
std::size_t cursor = start + node;
const auto terminalSize = ReadUleb(data, cursor, end);
if (terminalSize > end - cursor) throw std::runtime_error("export trie terminal out of bounds");
const auto children = cursor + terminalSize;
if (terminalSize != 0) {
MachOExport entry;
entry.Name = prefix;
entry.Flags = ReadUleb(data, cursor, children);
if (entry.Flags & kExportReexport) {
entry.Other = ReadUleb(data, cursor, children);
entry.ImportName = ReadTrieString(data, cursor, children);
} else {
entry.Address = ReadUleb(data, cursor, children);
if (entry.Flags & kExportStubAndResolver) entry.Other = ReadUleb(data, cursor, children);
}
out.push_back(std::move(entry));
}
cursor = children;
if (cursor >= end) throw std::runtime_error("export trie child count out of bounds");
const auto childCount = data[cursor++];
for (unsigned index = 0; index < childCount; ++index) {
const auto label = ReadTrieString(data, cursor, end);
const auto child = ReadUleb(data, cursor, end);
const auto length = prefix.size();
prefix += label;
ParseTrieNode(data, start, end, static_cast<std::size_t>(child), prefix, visited, out);
prefix.resize(length);
}
}
std::vector<MachOExport> ParseTrie(const std::vector<std::uint8_t>& binary, std::uint32_t offset, std::uint32_t size) {
RequireRange(binary, offset, size);
std::vector<MachOExport> exports;
if (size == 0) return exports;
std::string prefix;
std::set<std::size_t> visited;
ParseTrieNode(binary, offset, std::size_t{offset} + size, 0, prefix, visited, exports);
return exports;
}
class TrieBuilder {
public:
explicit TrieBuilder(const std::vector<MachOExport>& exports) {
for (const auto& entry : exports) Insert(entry);
}
std::vector<std::uint8_t> Build() {
std::vector<Node*> order;
Collect(&root, order);
for (bool changed = true; changed;) {
changed = false;
std::uint64_t offset = 0;
for (auto* node : order) {
if (node->Offset != offset) {
node->Offset = offset;
changed = true;
}
offset += NodeSize(*node);
}
}
std::vector<std::uint8_t> out;
for (auto* node : order) {
if (out.size() != node->Offset) throw std::runtime_error("export trie layout mismatch");
const auto terminal = TerminalBytes(*node);
WriteUleb(out, terminal.size());
out.insert(out.end(), terminal.begin(), terminal.end());
if (node->Children.size() > 255) throw std::runtime_error("export trie node has too many children");
out.push_back(static_cast<std::uint8_t>(node->Children.size()));
for (const auto& [label, child] : node->Children) {
out.insert(out.end(), label.begin(), label.end());
out.push_back(0);
WriteUleb(out, child->Offset);
}
}
while (out.size() % 8 != 0) out.push_back(0);
return out;
}
private:
struct Node {
std::vector<std::pair<std::string, std::unique_ptr<Node>>> Children;
std::optional<MachOExport> Entry;
std::uint64_t Offset = 0;
};
Node root;
void Insert(const MachOExport& entry) {
Node* node = &root;
std::string_view rest = entry.Name;
while (!rest.empty()) {
bool descended = false;
for (auto& [label, child] : node->Children) {
std::size_t common = 0;
while (common < label.size() && common < rest.size() && label[common] == rest[common]) ++common;
if (common == 0) continue;
if (common < label.size()) {
auto middle = std::make_unique<Node>();
middle->Children.emplace_back(label.substr(common), std::move(child));
label.resize(common);
child = std::move(middle);
}
node = child.get();
rest.remove_prefix(common);
descended = true;
break;
}
if (!descended) {
node->Children.emplace_back(std::string(rest), std::make_unique<Node>());
node = node->Children.back().second.get();
rest = {};
}
}
if (node->Entry) throw std::runtime_error("duplicate patched export name: " + entry.Name);
node->Entry = entry;
}
static void Collect(Node* node, std::vector<Node*>& order) {
order.push_back(node);
for (auto& [label, child] : node->Children) Collect(child.get(), order);
}
static std::vector<std::uint8_t> TerminalBytes(const Node& node) {
std::vector<std::uint8_t> bytes;
if (!node.Entry) return bytes;
const auto& entry = *node.Entry;
WriteUleb(bytes, entry.Flags);
if (entry.Flags & kExportReexport) {
WriteUleb(bytes, entry.Other);
bytes.insert(bytes.end(), entry.ImportName.begin(), entry.ImportName.end());
bytes.push_back(0);
} else {
WriteUleb(bytes, entry.Address);
if (entry.Flags & kExportStubAndResolver) WriteUleb(bytes, entry.Other);
}
return bytes;
}
static std::uint64_t NodeSize(const Node& node) {
const auto terminal = TerminalBytes(node).size();
std::uint64_t size = UlebSize(terminal) + terminal + 1;
for (const auto& [label, child] : node.Children) size += label.size() + 1 + UlebSize(child->Offset);
return size;
}
};
std::string StripUnderscore(const std::string& name) {
return !name.empty() && name[0] == '_' ? name.substr(1) : name;
}
bool IsGuestFacingImport(const std::string& name) {
using namespace Internal;
const bool hasNidPostfix = name.size() >= kNidPostfixLen && name.compare(name.size() - kNidPostfixLen, kNidPostfixLen, kNidPostfix) == 0;
const bool hasScePrefix = name.size() >= 3u &&
std::tolower(static_cast<unsigned char>(name[0])) == 's' &&
std::tolower(static_cast<unsigned char>(name[1])) == 'c' &&
std::tolower(static_cast<unsigned char>(name[2])) == 'e';
return hasNidPostfix || hasScePrefix;
}
std::vector<bool> DylibOrdinalsArePrx(const std::vector<std::uint8_t>& binary, const Image& image) {
std::vector<bool> result;
for (const auto offset : image.Commands) {
const auto command = Read<LoadCommand>(binary, offset);
if (command.Cmd != kLcLoadDylib && command.Cmd != kLcLoadWeakDylib && command.Cmd != kLcReexportDylib && command.Cmd != kLcLazyLoadDylib && command.Cmd != kLcLoadUpwardDylib) continue;
const auto nameOffset = Read<std::uint32_t>(binary, offset + 8);
if (nameOffset >= command.Size) throw std::runtime_error("dylib name out of bounds");
const auto name = Internal::ReadCStr(binary, offset + nameOffset);
result.push_back(name.size() >= 4 && name.compare(name.size() - 4, 4, ".prx") == 0);
}
return result;
}
void PatchChainedImports(std::vector<std::uint8_t>& binary, const Image& image) {
std::optional<LinkeditDataCommand> fixups;
for (const auto offset : image.Commands) {
const auto cmd = Read<LoadCommand>(binary, offset).Cmd;
if (cmd == kLcDyldChainedFixups) fixups = Read<LinkeditDataCommand>(binary, offset);
if ((cmd == kLcDyldInfo || cmd == kLcDyldInfoOnly)) {
const auto info = Read<DyldInfoCommand>(binary, offset);
if (info.BindSize != 0 || info.LazyBindSize != 0 || info.WeakBindSize != 0) throw std::runtime_error("Mach-O bind opcodes are not supported; link with chained fixups");
}
}
if (!fixups || fixups->DataSize == 0) return;
RequireRange(binary, fixups->DataOffset, fixups->DataSize);
const auto base = std::size_t{fixups->DataOffset};
const auto header = Read<ChainedFixupsHeader>(binary, base);
if (header.Version != 0) throw std::runtime_error("unsupported chained fixups version");
if (header.SymbolsFormat != 0) throw std::runtime_error("compressed chained fixup symbols are not supported");
const std::size_t entrySize = header.ImportsFormat == kImportFormatPlain ? 4 : header.ImportsFormat == kImportFormatAddend ? 8 : header.ImportsFormat == kImportFormatAddend64 ? 16 : 0;
if (entrySize == 0) throw std::runtime_error("unsupported chained import format");
if (header.ImportsOffset > fixups->DataSize || std::uint64_t{header.ImportsCount} * entrySize > fixups->DataSize - header.ImportsOffset || header.SymbolsOffset > fixups->DataSize)
throw std::runtime_error("chained imports out of bounds");
const auto symbols = base + header.SymbolsOffset;
const auto symbolsEnd = base + fixups->DataSize;
const auto prx = DylibOrdinalsArePrx(binary, image);
struct Import { std::uint32_t NameOffset; std::uint32_t Ordinal; };
std::vector<Import> imports;
for (std::uint32_t index = 0; index < header.ImportsCount; ++index) {
const auto at = base + header.ImportsOffset + index * entrySize;
if (header.ImportsFormat == kImportFormatAddend64) {
const auto raw = Read<std::uint64_t>(binary, at);
imports.push_back({static_cast<std::uint32_t>(raw >> 32), static_cast<std::uint32_t>(raw & 0xffff)});
} else {
const auto raw = Read<std::uint32_t>(binary, at);
imports.push_back({raw >> 9, raw & 0xff});
}
}
std::set<std::uint32_t> nameOffsets;
for (const auto& item : imports) nameOffsets.insert(item.NameOffset);
std::set<std::uint32_t> rewritten;
for (const auto& item : imports) {
const bool special = header.ImportsFormat == kImportFormatAddend64 ? item.Ordinal >= 0xfff0 : item.Ordinal >= 0xf0;
if (item.Ordinal == 0 || special || item.Ordinal > prx.size() || !prx[item.Ordinal - 1]) continue;
if (rewritten.contains(item.NameOffset)) continue;
const auto at = symbols + item.NameOffset;
if (at >= symbolsEnd) throw std::runtime_error("chained import name out of bounds");
const auto name = Internal::ReadCStr(binary, at);
if (at + name.size() >= symbolsEnd) throw std::runtime_error("unterminated chained import name");
const auto bare = StripUnderscore(name);
if (bare == name || !IsGuestFacingImport(bare)) continue;
const auto patched = "_" + ResolveOneName(bare);
if (patched.size() > name.size()) throw std::runtime_error("import NID longer than original name: " + name);
const auto inside = nameOffsets.upper_bound(item.NameOffset);
if (inside != nameOffsets.end() && *inside <= item.NameOffset + name.size()) throw std::runtime_error("chained import names share storage: " + name);
std::memcpy(binary.data() + at, patched.data(), patched.size());
std::fill(binary.begin() + static_cast<std::ptrdiff_t>(at + patched.size()), binary.begin() + static_cast<std::ptrdiff_t>(at + name.size() + 1), 0);
rewritten.insert(item.NameOffset);
}
}
void WriteTrie(std::vector<std::uint8_t>& binary, const Image& image, const TrieLocation& location, const std::vector<std::uint8_t>& trie) {
const auto oldOffset = Read<std::uint32_t>(binary, location.OffsetField);
const auto oldSize = Read<std::uint32_t>(binary, location.SizeField);
if (trie.size() <= oldSize) {
std::copy(trie.begin(), trie.end(), binary.begin() + oldOffset);
std::fill(binary.begin() + oldOffset + static_cast<std::ptrdiff_t>(trie.size()), binary.begin() + oldOffset + oldSize, 0);
Write(binary, location.SizeField, static_cast<std::uint32_t>(trie.size()));
return;
}
std::optional<std::size_t> linkedit;
for (const auto offset : image.Commands) {
const auto cmd = Read<LoadCommand>(binary, offset).Cmd;
if (cmd == kLcCodeSignature) throw std::runtime_error("signed Mach-O images cannot grow their export trie");
if (cmd != kLcSegment64) continue;
const auto segment = Read<SegmentCommand64>(binary, offset);
if (std::strncmp(segment.Name, "__LINKEDIT", sizeof(segment.Name)) == 0) linkedit = offset;
}
if (!linkedit) throw std::runtime_error("Mach-O image has no __LINKEDIT segment");
auto segment = Read<SegmentCommand64>(binary, *linkedit);
if (segment.FileOffset + segment.FileSize != binary.size()) throw std::runtime_error("__LINKEDIT does not end the file");
const auto newOffset = (binary.size() + 7) & ~std::size_t{7};
if (newOffset + trie.size() > 0xffffffffu) throw std::runtime_error("export trie offset overflow");
binary.resize(newOffset, 0);
binary.insert(binary.end(), trie.begin(), trie.end());
std::fill(binary.begin() + oldOffset, binary.begin() + oldOffset + oldSize, 0);
segment.FileSize = binary.size() - segment.FileOffset;
segment.VmSize = std::max(segment.VmSize, (segment.FileSize + kPageSize - 1) & ~(kPageSize - 1));
Write(binary, *linkedit, segment);
Write(binary, location.OffsetField, static_cast<std::uint32_t>(newOffset));
Write(binary, location.SizeField, static_cast<std::uint32_t>(trie.size()));
}
}
std::vector<MachOExport> ReadMachOExports(const std::vector<std::uint8_t>& binary) {
const auto image = ParseImage(binary);
const auto location = FindTrie(binary, image);
if (!location) return {};
return ParseTrie(binary, Read<std::uint32_t>(binary, location->OffsetField), Read<std::uint32_t>(binary, location->SizeField));
}
void MachONidPatcher::PatchNids(std::vector<std::uint8_t>& binary, const std::string& libraryName, const std::unordered_set<std::string>& excludedExports) const {
const auto image = ParseImage(binary);
const auto location = FindTrie(binary, image);
if (!location) throw std::runtime_error("no export trie");
auto exports = ParseTrie(binary, Read<std::uint32_t>(binary, location->OffsetField), Read<std::uint32_t>(binary, location->SizeField));
if (exports.empty()) throw std::runtime_error("no exported names");
std::vector<std::string> names;
names.reserve(exports.size());
for (const auto& entry : exports) {
if (entry.Name.empty() || entry.Name[0] != '_') throw std::runtime_error("exported name without a C underscore: " + entry.Name);
names.push_back(entry.Name.substr(1));
}
const auto nidMap = ResolveNids(names, libraryName, excludedExports);
for (std::size_t index = 0; index < exports.size(); ++index) {
const auto& name = names[index];
const bool marked = name.ends_with(Internal::kNidPostfix) || Internal::IsNidNoPatch(name) || Internal::IsNidNoPatchCut(name);
if ((exports[index].Flags & kExportWeakDefinition) != 0 && !marked) continue;
const auto found = nidMap.find(name);
if (found == nidMap.end()) throw std::runtime_error("symbol not in nid map: " + name);
exports[index].Name = "_" + found->second;
}
WriteTrie(binary, image, *location, TrieBuilder(exports).Build());
PatchChainedImports(binary, ParseImage(binary));
}
}

View File

@ -1,5 +1,6 @@
#include <nid/BinaryPatcherFactory.hpp>
#include <nid/ExportExclusions.hpp>
#include <nid/NativePath.hpp>
#include <fstream>
#include <iostream>
#include <stdexcept>
@ -9,20 +10,20 @@
namespace {
std::vector<std::uint8_t> _readFile(const std::string& path) {
std::ifstream f(path, std::ios::binary);
std::ifstream f(Nid::Internal::NativePath(path), std::ios::binary);
if (!f) throw std::runtime_error("cannot open: " + path);
return {std::istreambuf_iterator<char>(f), {}};
}
void _writeFile(const std::string& path, const std::vector<std::uint8_t>& data) {
std::ofstream f(path, std::ios::binary);
std::ofstream f(Nid::Internal::NativePath(path), std::ios::binary);
if (!f) throw std::runtime_error("cannot write: " + path);
f.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
}
}
int main(int argc, char* argv[]) {
int Run(int argc, char* argv[]) {
if (argc < 3) {
std::cerr << "Usage: nid_patcher <library_name> [--preserve-exports <unpatched-library>] <file> [file2 ...]\n";
return 1;
@ -65,3 +66,27 @@ int main(int argc, char* argv[]) {
return 0;
}
#ifdef _WIN32
int wmain(int argc, wchar_t* argv[]) {
try {
std::vector<std::string> values;
values.reserve(static_cast<std::size_t>(argc));
for (int index = 0; index < argc; ++index) {
const auto utf8 = std::filesystem::path(argv[index]).u8string();
values.emplace_back(utf8.begin(), utf8.end());
}
std::vector<char*> arguments;
arguments.reserve(values.size());
for (auto& value : values) arguments.push_back(value.data());
return Run(argc, arguments.data());
} catch (const std::exception& error) {
std::cerr << "FAIL: " << error.what() << '\n';
return 2;
}
}
#else
int main(int argc, char* argv[]) {
return Run(argc, argv);
}
#endif

View File

@ -0,0 +1,60 @@
#include <nid/NidPatcherUtils.hpp>
#include <cstdint>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <vector>
namespace {
void Require(bool condition) {
if (!condition) throw std::runtime_error("NID buffer validation failed");
}
template<typename TAction>
void RequireRejected(TAction action) {
try { action(); }
catch (const std::runtime_error&) { return; }
throw std::runtime_error("Malformed NID buffer was accepted");
}
}
int main() {
try {
using namespace Nid::Internal;
const std::vector<std::uint8_t> unterminated{'n', 'a', 'm', 'e'};
RequireRejected([&] { ReadCStr(unterminated, 0); });
RequireRejected([&] { ReadCStr(unterminated, 3); });
const std::vector<std::uint8_t> strings{'a', 0, 'b', 'c', 0};
Require(ReadCStr(strings, 0) == "a");
Require(ReadCStr(strings, 1).empty());
Require(ReadCStr(strings, 2) == "bc");
Require(ReadCStr(strings, 4).empty());
RequireRejected([&] { ReadCStr(strings, strings.size()); });
RequireRejected([&] { ReadCStr({}, 0); });
std::vector<std::uint8_t> bytes(8, 0xa5);
const std::uint64_t value = 0x1020304050607080;
Write(bytes, 0, value);
Require(Read<std::uint64_t>(bytes, 0) == value);
Write<std::uint32_t>(bytes, 4, 0x12345678);
Require(Read<std::uint32_t>(bytes, 4) == 0x12345678);
const auto before = bytes;
for (const auto offset : {std::size_t{5}, std::size_t{8}, std::size_t{9},
std::numeric_limits<std::size_t>::max(), std::numeric_limits<std::size_t>::max() - 1,
std::numeric_limits<std::size_t>::max() - 3}) {
RequireRejected([&] { Read<std::uint32_t>(bytes, offset); });
RequireRejected([&] { Write<std::uint32_t>(bytes, offset, 0); });
Require(bytes == before);
}
RequireRejected([&] { Read<std::uint64_t>(bytes, 1); });
std::vector<std::uint8_t> empty;
RequireRejected([&] { Read<std::uint8_t>(empty, 0); });
RequireRejected([&] { Write<std::uint8_t>(empty, 0, 0); });
std::cout << "NID buffer validation passed\n";
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}

View File

@ -0,0 +1,48 @@
import struct
import sys
import unittest
from pathlib import Path
from test_symbol_versions import build_image, symbols, patch, SHOFF
class ElfLayoutTests(unittest.TestCase):
def test_declared_layout_must_match_supported_tables(self):
changes = ((5, "B", 2), (0x3a, "H", 32),
(SHOFF + 64 + 56, "Q", 8),
(SHOFF + 64 + 32, "Q", len(symbols(False)) * 24 + 1),
(SHOFF + 128 + 4, "I", 1))
for offset, kind, value in changes:
with self.subTest(offset=offset, value=value):
image = build_image(symbols(False), False)
struct.pack_into("<" + kind, image, offset, value)
self.reject(image)
def test_table_ranges_and_links_are_checked(self):
changes = ((0x28, "Q", 0x10000),
(SHOFF + 64 + 24, "Q", 0xff0),
(SHOFF + 64 + 40, "I", 100),
(SHOFF + 128 + 24, "Q", 0xff0),
(SHOFF + 128 + 32, "Q", 0xffffffffffffffff))
for offset, kind, value in changes:
with self.subTest(offset=offset, value=value):
image = build_image(symbols(False), False)
struct.pack_into("<" + kind, image, offset, value)
self.reject(image)
def reject(self, image):
result, after = patch(PATCHER, bytes(image), "layout.so")
self.assertEqual(result.returncode, 2, (result.returncode, result.stderr))
self.assertRegex(result.stderr.decode(), "ELF|dynsym|dynstr")
self.assertEqual(after, image)
def test_valid_supported_layout_still_patches(self):
image = build_image(symbols(False), False)
result, after = patch(PATCHER, bytes(image), "valid-layout.so")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertNotEqual(after, image)
if __name__ == "__main__":
PATCHER = Path(sys.argv.pop(1)).resolve()
unittest.main()

View File

@ -0,0 +1,75 @@
import struct
import sys
import unittest
from pathlib import Path
from test_symbol_versions import build_image, symbols, patch, HASH_OFFSET, SHOFF, read_dynsym, gnu_hash
class GnuHashTests(unittest.TestCase):
def image(self, buckets=4, bloom=1, shift=6, symoffset=3):
image = build_image(symbols(False), False)
count = len(symbols(False))
struct.pack_into("<IIII", image, HASH_OFFSET, buckets, symoffset, bloom, shift)
size = 16 + 8 * bloom + 4 * buckets + 4 * max(0, count - symoffset)
struct.pack_into("<Q", image, SHOFF + 3 * 64 + 32, size)
return image
def test_non_power_of_two_bloom_is_rejected(self):
self.reject(self.image(bloom=3))
def test_hash_shift_outside_word_is_rejected(self):
self.reject(self.image(shift=32))
def test_unsafe_geometry_is_rejected(self):
for fields in ({"bloom": 0}, {"buckets": 0}, {"symoffset": 100}):
with self.subTest(fields=fields):
self.reject(self.image(**fields))
def test_declared_section_extent_is_checked(self):
for size in (12, 16, 0x10000):
with self.subTest(size=size):
image = self.image()
struct.pack_into("<Q", image, SHOFF + 3 * 64 + 32, size)
self.reject(image)
def reject(self, image):
result, after = patch(PATCHER, bytes(image), "geometry.so")
self.assertEqual(result.returncode, 2, (result.returncode, result.stderr))
self.assertIn(b"gnu.hash", result.stderr)
self.assertEqual(after, image)
def test_rebuilt_hash_finds_every_export(self):
image = self.image(bloom=2)
result, after = patch(PATCHER, image, "valid.so")
self.assertEqual(result.returncode, 0, result.stderr)
entries = read_dynsym(after)
buckets, first, bloom, shift = struct.unpack_from("<4I", after, HASH_OFFSET)
bucket_offset = HASH_OFFSET + 16 + bloom * 8
chain_offset = bucket_offset + buckets * 4
for index in range(first, len(entries)):
name = entries[index][0]
hashed = gnu_hash(name)
word = struct.unpack_from("<Q", after, HASH_OFFSET + 16 + ((hashed // 64) % bloom) * 8)[0]
self.assertTrue(word & (1 << (hashed % 64)))
self.assertTrue(word & (1 << ((hashed >> shift) % 64)))
start = struct.unpack_from("<I", after, bucket_offset + (hashed % buckets) * 4)[0]
found = False
for candidate in range(start, len(entries)):
value = struct.unpack_from("<I", after, chain_offset + (candidate - first) * 4)[0]
if (value | 1) == (hashed | 1) and entries[candidate][0] == name:
found = True
if value & 1:
break
self.assertTrue(found, name)
def test_empty_hash_with_no_buckets_is_supported(self):
image = self.image(buckets=0, symoffset=len(symbols(False)))
result, after = patch(PATCHER, image, "empty.so")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(struct.unpack_from("<I", after, HASH_OFFSET)[0], 0)
if __name__ == "__main__":
PATCHER = Path(sys.argv.pop(1)).resolve()
unittest.main()

View File

@ -0,0 +1,235 @@
"""Check nid_patcher on small byte-built Mach-O dylibs: the export trie, the chained imports and what it refuses."""
import hashlib
import struct
import subprocess
import sys
import tempfile
from pathlib import Path
SUFFIX = bytes([0x51, 0x8D, 0x64, 0xA6, 0x35, 0xDE, 0xD8, 0xC1, 0xE6, 0xB0, 0x39, 0xB1, 0xC3, 0xE5, 0x52, 0x30])
BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
LC_SEGMENT_64 = 0x19
LC_LOAD_DYLIB = 0x0C
LC_CODE_SIGNATURE = 0x1D
LC_DYLD_INFO_ONLY = 0x80000022
LC_DYLD_EXPORTS_TRIE = 0x80000033
LC_DYLD_CHAINED_FIXUPS = 0x80000034
EXPORT_WEAK = 0x04
PAGE = 0x1000
def nid(name):
digest = hashlib.sha1(name.encode() + SUFFIX).digest()
reversed_bytes = digest[:8][::-1]
text = ""
for index in (0, 3):
triple = (reversed_bytes[index] << 16) | (reversed_bytes[index + 1] << 8) | reversed_bytes[index + 2]
text += BASE64[(triple >> 18) & 63] + BASE64[(triple >> 12) & 63] + BASE64[(triple >> 6) & 63] + BASE64[triple & 63]
tail = (reversed_bytes[6] << 16) | (reversed_bytes[7] << 8)
return text + BASE64[(tail >> 18) & 63] + BASE64[(tail >> 12) & 63] + BASE64[(tail >> 6) & 63]
def uleb(value):
out = bytearray()
while True:
byte = value & 0x7F
value >>= 7
out.append(byte | (0x80 if value else 0))
if not value:
return bytes(out)
def read_uleb(data, position):
value = shift = 0
while True:
byte = data[position]
position += 1
value |= (byte & 0x7F) << shift
if not byte & 0x80:
return value, position
shift += 7
def build_trie(entries):
offsets = [0] * len(entries)
for _ in range(8):
root = bytearray(b"\0") + bytes([len(entries)])
for (name, _, _), offset in zip(entries, offsets):
root += name.encode() + b"\0" + uleb(offset)
nodes = []
for name, flags, address in entries:
terminal = uleb(flags) + uleb(address)
nodes.append(uleb(len(terminal)) + terminal + b"\0")
position, expected = len(root), []
for node in nodes:
expected.append(position)
position += len(node)
if expected == offsets:
break
offsets = expected
trie = bytes(root) + b"".join(nodes)
return trie + bytes(-len(trie) % 8)
def parse_trie(data, start, size):
found = {}
def walk(node, prefix):
position = start + node
terminal, position = read_uleb(data, position)
children = position + terminal
if terminal:
flags, position = read_uleb(data, position)
address, position = read_uleb(data, position)
found[prefix] = (flags, address)
count = data[children]
position = children + 1
for _ in range(count):
end = data.index(0, position)
label = data[position:end].decode()
child, position = read_uleb(data, end + 1)
walk(child, prefix + label)
if size:
walk(0, "")
return found
def build_fixups(imports):
symbols = bytearray(b"\0")
entries = []
for name, ordinal in imports:
entries.append(ordinal | (len(symbols) << 9))
symbols += name.encode() + b"\0"
imports_offset = 32
header = struct.pack("<7I", 0, 28, imports_offset, imports_offset + 4 * len(imports), len(imports), 1, 0)
blob = header + struct.pack("<I", 0) + b"".join(struct.pack("<I", entry) for entry in entries) + bytes(symbols)
return blob + bytes(-len(blob) % 8)
def dylib_command(path):
name = path.encode() + b"\0"
size = (24 + len(name) + 7) & ~7
return struct.pack("<IIIIII", LC_LOAD_DYLIB, size, 24, 2, 0x10000, 0x10000) + name.ljust(size - 24, b"\0")
def build_dylib(exports, imports, signed=False, bind_opcodes=False):
trie = build_trie(exports)
fixups = build_fixups(imports)
linkedit = bytearray(trie + fixups)
trie_command = (struct.pack("<IIII", LC_DYLD_EXPORTS_TRIE, 16, PAGE, len(trie)))
fixups_command = struct.pack("<IIII", LC_DYLD_CHAINED_FIXUPS, 16, PAGE + len(trie), len(fixups))
if bind_opcodes:
trie_command = struct.pack("<IIIIIIIIIIII", LC_DYLD_INFO_ONLY, 48, 0, 0, PAGE, 8, 0, 0, 0, 0, PAGE, len(trie))
extra = [trie_command, fixups_command, dylib_command("@rpath/libkernel.prx"), dylib_command("/usr/lib/libSystem.B.dylib")]
if signed:
extra.append(struct.pack("<IIII", LC_CODE_SIGNATURE, 16, PAGE + len(linkedit), 0))
text = struct.pack("<II16sQQQQiiII", LC_SEGMENT_64, 72, b"__TEXT", 0, PAGE, 0, PAGE, 5, 5, 0, 0)
link = struct.pack("<II16sQQQQiiII", LC_SEGMENT_64, 72, b"__LINKEDIT", PAGE, PAGE, PAGE, len(linkedit), 1, 1, 0, 0)
body = text + link + b"".join(extra)
header = struct.pack("<IIIIIIII", 0xFEEDFACF, 0x01000007, 3, 6, 2 + len(extra), len(body), 0, 0)
image = bytearray(header + body)
image += bytes(PAGE - len(image))
image += linkedit
return bytes(image)
def command_fields(data):
offset, found = 32, {}
for _ in range(struct.unpack_from("<I", data, 16)[0]):
cmd, size = struct.unpack_from("<II", data, offset)
found.setdefault(cmd, []).append(offset)
offset += size
return found
def segment(data, name):
for offset in command_fields(data)[LC_SEGMENT_64]:
fields = struct.unpack_from("<16sQQQQ", data, offset + 8)
if fields[0].rstrip(b"\0").decode() == name:
return offset, fields[1:]
raise AssertionError(name)
def chained_imports(data):
offset = command_fields(data)[LC_DYLD_CHAINED_FIXUPS][0]
base, size = struct.unpack_from("<II", data, offset + 8)
_, _, imports_offset, symbols_offset, count, _, _ = struct.unpack_from("<7I", data, base)
result = []
for index in range(count):
raw, = struct.unpack_from("<I", data, base + imports_offset + 4 * index)
start = base + symbols_offset + (raw >> 9)
result.append((data[start:data.index(0, start)].decode(), raw & 0xFF))
return result
def patch(patcher, directory, name, image):
path = Path(directory) / name
path.write_bytes(image)
result = subprocess.run([str(patcher), "libtest", str(path)], capture_output=True, text=True, timeout=30)
return result, path
def exports_of(data):
offset = command_fields(data)[LC_DYLD_EXPORTS_TRIE][0]
start, size = struct.unpack_from("<II", data, offset + 8)
return parse_trie(data, start, size)
def check_shrinking(patcher, directory):
exports = [("_puts_nid_postfix", 0, 0x100), ("_exit_nid_postfix", 0, 0x108), ("_weak_inline", EXPORT_WEAK, 0x110)]
imports = [("_malloc", 2), ("_puts_nid_postfix", 1), ("_sceKernelFoo", 1), ("_helper", 1), ("_exit_nid_postfix", 2)]
result, path = patch(patcher, directory, "shrink.dylib", build_dylib(exports, imports))
assert result.returncode == 0, (result.stdout, result.stderr)
data = path.read_bytes()
assert exports_of(data) == {"_" + nid("puts"): (0, 0x100), "_" + nid("exit"): (0, 0x108), "_weak_inline": (EXPORT_WEAK, 0x110)}, exports_of(data)
assert chained_imports(data) == [("_malloc", 2), ("_" + nid("puts"), 1), ("_" + nid("sceKernelFoo"), 1), ("_helper", 1), ("_exit_nid_postfix", 2)], chained_imports(data)
assert len(data) == len(build_dylib(exports, imports)), "the image changed size"
def check_growing(patcher, directory):
original = build_dylib([("_ab", 0, 0x100), ("_cd", 0, 0x108)], [])
result, path = patch(patcher, directory, "grow.dylib", original)
assert result.returncode == 0, (result.stdout, result.stderr)
data = path.read_bytes()
assert exports_of(data) == {"_" + nid("ab"): (0, 0x100), "_" + nid("cd"): (0, 0x108)}, exports_of(data)
offset, (vmaddr, vmsize, fileoff, filesize) = segment(data, "__LINKEDIT")
assert fileoff + filesize == len(data) and vmsize >= filesize and len(data) > len(original), (fileoff, filesize, len(data))
trie_offset, trie_size = struct.unpack_from("<II", data, command_fields(data)[LC_DYLD_EXPORTS_TRIE][0] + 8)
assert trie_offset >= len(original) and trie_offset + trie_size <= len(data) and trie_offset % 8 == 0, (trie_offset, trie_size)
def check_preserved(patcher, directory):
reference = Path(directory) / "reference.dylib"
reference.write_bytes(build_dylib([("_puts", 0, 0x100)], []))
path = Path(directory) / "preserve.dylib"
path.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100), ("_exit_nid_postfix", 0, 0x108)], []))
result = subprocess.run([str(patcher), "libtest", "--preserve-exports", str(reference), str(path)], capture_output=True, text=True, timeout=30)
assert result.returncode == 0, (result.stdout, result.stderr)
assert exports_of(path.read_bytes()) == {"_puts_nid_postfix": (0, 0x100), "_" + nid("exit"): (0, 0x108)}, exports_of(path.read_bytes())
def check_refusals(patcher, directory):
growing = [("_ab", 0, 0x100), ("_cd", 0, 0x108)]
result, _ = patch(patcher, directory, "signed.dylib", build_dylib(growing, [], signed=True))
assert result.returncode != 0 and "signed Mach-O images cannot grow their export trie" in result.stdout + result.stderr, (result.stdout, result.stderr)
result, _ = patch(patcher, directory, "opcodes.dylib", build_dylib([("_puts_nid_postfix", 0, 0x100)], [], bind_opcodes=True))
assert result.returncode != 0 and "bind opcodes are not supported" in result.stdout + result.stderr, (result.stdout, result.stderr)
result, _ = patch(patcher, directory, "long.dylib", build_dylib([("_puts_nid_postfix", 0, 0x100)], [("_sceXy", 1)]))
assert result.returncode != 0 and "import NID longer than original name" in result.stdout + result.stderr, (result.stdout, result.stderr)
def main():
patcher = Path(sys.argv[1]).resolve()
with tempfile.TemporaryDirectory(prefix="anyps5-macho-nid-") as directory:
check_shrinking(patcher, directory)
check_growing(patcher, directory)
check_preserved(patcher, directory)
check_refusals(patcher, directory)
print("NID patcher Mach-O tests passed")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,56 @@
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from test_macho_nids import build_dylib, exports_of, nid
PATCHER = Path(sys.argv.pop(1)).resolve()
class NativePathTests(unittest.TestCase):
def invoke(self, *arguments):
return subprocess.run([str(PATCHER), "libtest", *map(str, arguments)],
capture_output=True, encoding="utf-8", errors="replace", timeout=10)
def test_non_ascii_directory_and_filename_patch_the_intended_file(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary) / "\u6e2c\u8a66"
root.mkdir()
file = root / "\u043c\u043e\u0434\u0443\u043b\u044c.prx"
file.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100)], []))
result = self.invoke(file)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(exports_of(file.read_bytes()), {"_" + nid("puts"): (0, 0x100)})
self.assertIn(str(file), result.stdout)
self.assertEqual(list(root.iterdir()), [file])
def test_non_ascii_export_reference_preserves_the_named_export(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
reference = root / "\u6e2c\u8a66-reference.prx"
original = build_dylib([("_puts", 0, 0x100)], [])
reference.write_bytes(original)
file = root / "target.prx"
file.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100), ("_exit_nid_postfix", 0, 0x108)], []))
result = self.invoke("--preserve-exports", reference, file)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(exports_of(file.read_bytes()), {"_puts_nid_postfix": (0, 0x100), "_" + nid("exit"): (0, 0x108)})
self.assertEqual(reference.read_bytes(), original)
def test_missing_unicode_input_does_not_modify_another_file(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
existing = root / "existing.prx"
existing.write_bytes(b"unchanged")
missing = root / "\u6e2c\u8a66-missing.prx"
result = self.invoke(missing)
self.assertEqual(result.returncode, 2)
self.assertIn(str(missing), result.stderr)
self.assertFalse(missing.exists())
self.assertEqual(existing.read_bytes(), b"unchanged")
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,69 @@
import struct
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from test_macho_nids import build_dylib, exports_of, nid
def reference(*, headers=False, address=0x2000, ordinal=0):
image = bytearray(1280)
image[:2] = b"MZ"
struct.pack_into("<I", image, 0x3c, 0x40)
struct.pack_into("<IHHIIIHH", image, 0x40, 0x4550, 0x8664, 2, 0, 0, 0, 240, 0x2022)
optional = 0x58
struct.pack_into("<H", image, optional, 0x20b)
struct.pack_into("<I", image, optional + 60, 512)
struct.pack_into("<I", image, optional + 108, 16)
start, rva = (416, 416) if headers else (512, 0x1000)
struct.pack_into("<II", image, optional + 112, rva, 80)
for index, (name, va, offset, size) in enumerate(((b".edata", 0x1000, 512, 256), (b".text", 0x2000, 768, 512))):
struct.pack_into("<8sIIIIIIHHI", image, optional + 240 + index * 40,
name, size, va, size, offset, 0, 0, 0, 0, 0x40000040)
struct.pack_into("<IIHHIIIIIII", image, start, 0, 0, 0, 0, rva + 50, 1, 1, 1, rva + 40, rva + 44, rva + 48)
struct.pack_into("<IIH", image, start + 40, address, rva + 50, ordinal)
name = b"puts_nid_postfix\0"
image[start + 50:start + 50 + len(name)] = name
return image
class ReferenceTests(unittest.TestCase):
def patch_with_reference(self, data):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source, ref = root / "target.dylib", root / "reference.bin"
original = build_dylib([("_puts_nid_postfix", 0, 0x100), ("_exit_nid_postfix", 0, 0x108)], [])
source.write_bytes(original)
ref.write_bytes(data)
result = subprocess.run([str(PATCHER), "libc", str(source), "--preserve-exports", str(ref)], capture_output=True, text=True)
self.assertEqual(ref.read_bytes(), data)
return result, source.read_bytes(), original
def test_header_resident_export_tables(self):
result, image, _ = self.patch_with_reference(reference(headers=True))
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(exports_of(image), {"_puts_nid_postfix": (0, 0x100), "_" + nid("exit"): (0, 0x108)})
def test_section_resident_export_tables(self):
result, image, _ = self.patch_with_reference(reference())
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertIn("_puts_nid_postfix", exports_of(image))
def test_null_function_slot_does_not_preserve_a_name(self):
result, image, original = self.patch_with_reference(reference(address=0))
self.assertNotEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertIn("no named exports", result.stdout + result.stderr)
self.assertEqual(image, original)
def test_invalid_name_ordinal_is_rejected_without_changing_target(self):
result, image, original = self.patch_with_reference(reference(ordinal=1))
self.assertNotEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertIn("ordinal", result.stdout + result.stderr)
self.assertEqual(image, original)
if __name__ == "__main__":
PATCHER = Path(sys.argv.pop(1)).resolve()
unittest.main()

View File

@ -0,0 +1,58 @@
import struct
import sys
import unittest
from pathlib import Path
from test_symbol_versions import build_image, symbols, patch, SHOFF, DYNSYM_OFFSET, read_dynsym, sections, DEFINITIONS
class SharedStringTests(unittest.TestCase):
def test_dynamic_names_keep_original_string_when_export_shares_offset(self):
for tag in (1, 14, 15, 29):
with self.subTest(tag=tag):
data = build_image(symbols(False), False)
name_offset = struct.unpack_from("<I", data, DYNSYM_OFFSET + 3 * 24)[0]
struct.pack_into("<H", data, 0x3c, 5)
struct.pack_into("<IIQQQQIIQQ", data, SHOFF + 4 * 64, 0, 6, 2, 0, 0x580, 32, 2, 0, 8, 16)
struct.pack_into("<qQqQ", data, 0x580, tag, name_offset, 0, 0)
result, after = patch(PATCHER, bytes(data), "shared-dynamic.so")
self.assertEqual(result.returncode, 0, result.stderr)
strings = sections(after)[2]
new_offset = struct.unpack_from("<Q", after, 0x588)[0]
start = strings[4] + new_offset
self.assertEqual(after[start:after.index(0, start)].decode(), DEFINITIONS[0][0])
renamed = next(entry[0] for entry in read_dynsym(after) if entry[2] == DEFINITIONS[0][2])
self.assertNotEqual(renamed, DEFINITIONS[0][0])
def test_version_requirement_strings_keep_original_names(self):
data = build_image(symbols(False), False)
name_offset = struct.unpack_from("<I", data, DYNSYM_OFFSET + 3 * 24)[0]
struct.pack_into("<H", data, 0x3c, 5)
struct.pack_into("<IIQQQQIIQQ", data, SHOFF + 4 * 64, 0, 0x6ffffffe, 2, 0, 0x580, 32, 2, 1, 8, 0)
struct.pack_into("<HHIII", data, 0x580, 1, 1, name_offset, 16, 0)
struct.pack_into("<IHHII", data, 0x590, 0, 0, 2, name_offset, 0)
result, after = patch(PATCHER, bytes(data), "shared-version.so")
self.assertEqual(result.returncode, 0, result.stderr)
strings = sections(after)[2]
for field in (0x584, 0x598):
offset = struct.unpack_from("<I", after, field)[0]
start = strings[4] + offset
self.assertEqual(after[start:after.index(0, start)].decode(), DEFINITIONS[0][0])
renamed = next(entry[0] for entry in read_dynsym(after) if entry[2] == DEFINITIONS[0][2])
self.assertNotEqual(renamed, DEFINITIONS[0][0])
def test_local_symbol_keeps_name_shared_with_renamed_global(self):
entries = symbols(False)
entries[1] = (DEFINITIONS[0][0], 1, 9, 2, 0x1500)
data = build_image(entries, False)
data[DYNSYM_OFFSET + 24 + 4] = 2
result, after = patch(PATCHER, bytes(data), "shared-local.so")
self.assertEqual(result.returncode, 0, result.stderr)
names = {value: name for name, _, value in read_dynsym(after)}
self.assertEqual(names[0x1500], DEFINITIONS[0][0])
self.assertNotEqual(names[DEFINITIONS[0][2]], DEFINITIONS[0][0])
if __name__ == "__main__":
PATCHER = Path(sys.argv.pop(1)).resolve()
unittest.main()

View File

@ -0,0 +1,76 @@
import struct
import sys
import unittest
from pathlib import Path
from test_symbol_versions import build_image, symbols, patch, SHOFF, DYNSTR_OFFSET, sections
VERNEED = 0x580
def image(*, auxiliary=16, count=1, size=32, version=1, auxnext=0, nextrecord=0):
data = build_image(symbols(False), False)
strings = sections(data)[2]
filename = strings[5]
names = b"libfixture.so\0FIXTURE_1\0"
data[DYNSTR_OFFSET + filename:DYNSTR_OFFSET + filename + len(names)] = names
struct.pack_into("<Q", data, SHOFF + 2 * 64 + 32, filename + len(names))
struct.pack_into("<H", data, 0x3c, 5)
struct.pack_into("<IIQQQQIIQQ", data, SHOFF + 4 * 64, 0, 0x6ffffffe, 2, 0, VERNEED, size, 2, 1, 8, 0)
struct.pack_into("<HHIII", data, VERNEED, version, count, filename, auxiliary, nextrecord)
struct.pack_into("<IHHII", data, VERNEED + auxiliary, 0, 0, 2, filename + len(b"libfixture.so\0"), auxnext)
return data
class VersionRequirementsTests(unittest.TestCase):
def test_auxiliary_record_cannot_leave_declared_section(self):
self.reject(image(auxiliary=32))
def test_auxiliary_count_must_match_chain(self):
self.reject(image(count=2))
def test_unsupported_structure_version_is_rejected(self):
self.reject(image(version=2))
def test_invalid_forward_links_and_section_ranges_are_rejected(self):
for fields in ({"auxnext": 16}, {"nextrecord": 64}, {"size": 15},
{"size": 0x10000}, {"auxiliary": 8}, {"count": 2, "auxnext": 8}):
with self.subTest(fields=fields):
self.reject(image(**fields))
def test_valid_multiple_auxiliaries_and_requirements(self):
data = image(count=2, size=80, auxnext=16, nextrecord=48)
original_name = struct.unpack_from("<I", data, VERNEED + 24)[0]
original_file = struct.unpack_from("<I", data, VERNEED + 4)[0]
struct.pack_into("<IHHII", data, VERNEED + 32, 0, 0, 3, original_name, 0)
struct.pack_into("<HHIII", data, VERNEED + 48, 1, 1, original_file, 16, 0)
struct.pack_into("<IHHII", data, VERNEED + 64, 0, 0, 4, original_name, 0)
result, after = patch(PATCHER, bytes(data), "multiple-versions.so")
self.assertEqual(result.returncode, 0, result.stderr)
strings = sections(after)[2]
for position, expected in ((4, b"libfixture.so"), (24, b"FIXTURE_1"),
(40, b"FIXTURE_1"), (52, b"libfixture.so"), (72, b"FIXTURE_1")):
offset = struct.unpack_from("<I", after, VERNEED + position)[0]
start = strings[4] + offset
self.assertEqual(after[start:after.index(0, start)], expected)
def reject(self, data):
result, after = patch(PATCHER, bytes(data), "versions.so")
self.assertEqual(result.returncode, 2, (result.returncode, result.stderr))
self.assertIn(b"version_r", result.stderr)
self.assertEqual(after, data)
def test_valid_names_are_preserved_when_strings_are_rebuilt(self):
data = image()
result, after = patch(PATCHER, bytes(data), "valid-versions.so")
self.assertEqual(result.returncode, 0, result.stderr)
strings = sections(after)[2]
for position, expected in ((VERNEED + 4, b"libfixture.so"), (VERNEED + 16 + 8, b"FIXTURE_1")):
offset = struct.unpack_from("<I", after, position)[0]
start = strings[4] + offset
self.assertEqual(after[start:after.index(0, start)], expected)
if __name__ == "__main__":
PATCHER = Path(sys.argv.pop(1)).resolve()
unittest.main()

View File

@ -1,54 +0,0 @@
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI ErrorDialogClose(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ErrorDialogOpen(const void* param) {
(void)param;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareGetCurrentStatus(uint32_t feature_flag, ShareCurrentStatus* status) {
(void)feature_flag;
(void)status;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareInitialize(size_t heap_size, int thread_priority, uint64_t affinity_mask) {
(void)heap_size;
(void)thread_priority;
(void)affinity_mask;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareTerminate(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SystemServiceParamGetInt(int param_id, int* value) {
(void)param_id;
(void)value;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SystemServiceParamGetString(int param_id, char* buf, size_t buf_size) {
(void)param_id;
(void)buf;
(void)buf_size;
NotImplemented_nid_no_patch(__func__);
return 0;
}
}

View File

@ -1,35 +0,0 @@
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI RemotePlayGetConnectionStatus(int user_id, int* status) {
(void)user_id;
(void)status;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareGetCurrentStatus(uint32_t feature_flag, ShareCurrentStatus* status) {
(void)feature_flag;
(void)status;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareInitialize(size_t heap_size, int thread_priority, uint64_t affinity_mask) {
(void)heap_size;
(void)thread_priority;
(void)affinity_mask;
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI ShareTerminate(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
}

View File

@ -53,12 +53,15 @@ int APS5_VABI sceAcm_ConvReverb_SharedInput(void) {
return 0;
}
int APS5_VABI sceAcm_FFT() {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceAcm_FFT(void) {
return 0;
}
int APS5_VABI sceAcm_Panner() {
int APS5_VABI sceAcm_Panner(void) {
return 0;
}
int APS5_VABI sceAcmBatchJobPriority(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}

View File

@ -4,17 +4,34 @@
#include "prx/libSceAgc/Command/include/Memory.hpp"
#include "prx/libSceAgc/Command/include/Packet.hpp"
#include "prx/libSceAgc/DcbState/include/Marker.hpp"
#include "prx/libSceAgcDriver/Execution/include/VideoOutput.hpp"
#include "prx/libSceAgcDriver/Resource/include/Registration.hpp"
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
std::uint32_t* RejectUnregisteredWorkloadStream(CommandBuffer* buf, std::uint32_t streamId, const char* function) {
if (buf == nullptr || !AgcDriverWorkloadStreamRegistered_nid_postfix(streamId)) return nullptr;
NotImplemented_nid_no_patch(function);
return nullptr;
}
}
extern "C" {
// unknown signature
void* APS5_VABI sceAgcAcbAtomicGds_0900(void) {
NotImplemented_nid_no_patch(__func__);
return nullptr;
std::uint32_t* APS5_VABI sceAgcAcbAtomicGds_0900(CommandBuffer* buf, std::uint32_t control, std::uint32_t mode, std::uint32_t gdsOp, std::uint32_t src, std::uint16_t offset, std::uint16_t index, std::uint32_t mask, std::uint32_t data, std::uint64_t compareData, std::uint64_t extraData) {
const auto operation = (control & 0xffu) | ((control & 0x200u) << 7u) |
((control & 0x20u) << 13u) | ((control & 0x40u) << 14u) |
((control & 0x20u) == 0 && mode == 1 ? 0x20000u : 0u);
return Agc::Command::Emit(buf, 0x1du, {
operation, ((gdsOp & 1u) << 8u) | (src & 0x3fu), offset, index,
mask & 0x00ff00ffu, data, static_cast<std::uint32_t>(compareData),
static_cast<std::uint32_t>(compareData >> 32u), static_cast<std::uint32_t>(extraData),
static_cast<std::uint32_t>(extraData >> 32u)}, __func__);
}
std::uint32_t* APS5_VABI sceAgcAcbJump(CommandBuffer* buf, std::uint8_t cachePolicy, const std::uint32_t* target, std::uint32_t sizeInDwords) {
@ -46,11 +63,12 @@ std::uint32_t APS5_VABI sceAgcAcbRewindGetSize() {
}
std::uint32_t* APS5_VABI sceAgcAcbWaitUntilSafeForRendering(CommandBuffer* buf, std::uint32_t videoOutHandle, std::uint32_t displayBufferIndex) {
(void)buf;
(void)videoOutHandle;
(void)displayBufferIndex;
NotImplemented_nid_no_patch(__func__);
return nullptr;
auto* packet = Agc::Command::Allocate(buf, AgcDriver::RenderingWaitPacketWords, __func__);
packet[0] = AgcDriver::RenderingWaitPacketHeader;
packet[1] = videoOutHandle;
packet[2] = displayBufferIndex;
packet[3] = 0;
return packet;
}
std::uint32_t* APS5_VABI sceAgcAcbSetFlip(CommandBuffer* buf, std::uint32_t videoOutHandle, std::int32_t displayBufferIndex, std::uint32_t flipMode, std::int64_t flipArg) {
@ -63,6 +81,21 @@ std::uint32_t* APS5_VABI sceAgcAcbSetFlip(CommandBuffer* buf, std::uint32_t vide
return nullptr;
}
std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadsActive(CommandBuffer* buf, std::uint32_t streamId, const std::uint32_t* workloadIds, std::uint32_t workloadCount) {
(void)workloadIds;
(void)workloadCount;
return RejectUnregisteredWorkloadStream(buf, streamId, __func__);
}
std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadComplete(CommandBuffer* buf, std::uint32_t streamId, std::uint32_t workloadId) {
(void)workloadId;
return RejectUnregisteredWorkloadStream(buf, streamId, __func__);
}
std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadStreamInactive(CommandBuffer* buf, std::uint32_t streamId) {
return RejectUnregisteredWorkloadStream(buf, streamId, __func__);
}
uint32_t* APS5_VABI sceAgcAcbPushMarker(CommandBuffer* buf, const char* str, uint32_t color) {
(void)color;
return Agc::Marker::Push(buf, str, __func__);

View File

@ -29,9 +29,11 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Predication.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Registers.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Workload.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/PacketInfo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Platform.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/RegisterDefaults.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Semaphore.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/ShaderFusion.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Suspend.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Patch/src/CondExec.cpp
@ -46,6 +48,7 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/Predication/src/Predication.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/CreateShader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/GsOversubscription.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/GsPrimPayload.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/InterpolantMapping.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/LinkShaders.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/src/PrimState.cpp
@ -67,7 +70,7 @@ endforeach()
add_test_executable(agc_command_tests EXCLUDE_FROM_ALL tests/Commands.cpp)
target_include_directories(agc_command_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_command_tests PRIVATE libSceAgc libc)
target_link_libraries(agc_command_tests PRIVATE libSceAgc libSceAgcDriver libc)
configure_windows_unwind(agc_command_tests)
if(BUILD_TESTING)
set_target_properties(agc_command_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
@ -93,6 +96,19 @@ if(BUILD_TESTING)
endif()
endif()
add_test_executable(agc_semaphore_tests EXCLUDE_FROM_ALL tests/Semaphore.cpp)
target_include_directories(agc_semaphore_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_semaphore_tests PRIVATE libSceAgc libc)
configure_windows_unwind(agc_semaphore_tests)
if(BUILD_TESTING)
set_target_properties(agc_semaphore_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
add_test(NAME agc_semaphore_tests COMMAND agc_semaphore_tests)
if(WIN32)
set_tests_properties(agc_semaphore_tests PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
add_test_executable(agc_packet_info_tests EXCLUDE_FROM_ALL tests/PacketInfo.cpp)
target_include_directories(agc_packet_info_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_packet_info_tests PRIVATE libSceAgc libc)
@ -209,7 +225,7 @@ if(BUILD_TESTING)
endif()
add_test_executable(agc_shader_fusion_tests EXCLUDE_FROM_ALL tests/ShaderFusion.cpp)
target_include_directories(agc_shader_fusion_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/core/shader/recompiler ${CMAKE_SOURCE_DIR}/3rdparty/Vulkan-Headers/include ${CMAKE_SOURCE_DIR}/3rdparty/SPIRV-Headers/include)
target_include_directories(agc_shader_fusion_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/core/shader/recompiler ${ANYPS5_VULKAN_HEADERS_INCLUDE_DIR} ${ANYPS5_SPIRV_HEADERS_INCLUDE_DIR})
target_link_libraries(agc_shader_fusion_tests PRIVATE libSceAgc libSceAgcDriver libc)
set_target_properties(agc_shader_fusion_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_shader_fusion_tests)
@ -290,6 +306,22 @@ if(BUILD_TESTING)
endif()
endif()
add_test_executable(agc_gs_prim_payload_tests EXCLUDE_FROM_ALL
tests/GsPrimPayload.cpp
Shader/src/GsPrimPayload.cpp
)
target_include_directories(agc_gs_prim_payload_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_gs_prim_payload_tests PRIVATE libc)
configure_windows_unwind(agc_gs_prim_payload_tests)
if(BUILD_TESTING)
set_target_properties(agc_gs_prim_payload_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
add_test(NAME agc_gs_prim_payload_tests COMMAND agc_gs_prim_payload_tests)
if(WIN32)
set_tests_properties(agc_gs_prim_payload_tests PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
add_test_executable(agc_dma_data_tests EXCLUDE_FROM_ALL
tests/DmaData.cpp
Command/src/Packet.cpp

View File

@ -85,7 +85,7 @@ void ValidatePacket(const std::uint32_t* packet, std::uint32_t opcode, std::uint
}
std::uint32_t* WriteNop(CommandBuffer* buffer, std::uint32_t count, const char* function) {
const auto header = Header(0x10u, count);
const auto header = count == 1 ? 0xffff1000u : Header(0x10u, count);
auto* packet = Allocate(buffer, count, function);
packet[0] = header;
std::fill_n(packet + 1, count - 1u, 0u);

View File

@ -20,7 +20,7 @@ uint32_t* APS5_VABI sceAgcDcbSetBaseIndirectArgs(CommandBuffer* buf, uint32_t sh
// SET_BASE with base index 1; header bit 1 selects the dispatch (compute) base over the draw base.
Agc::Command::CheckBits(shader_type, 1, __func__);
const auto address = reinterpret_cast<std::uintptr_t>(indirect_base_addr);
Agc::Command::CheckAddress(address, 8, __func__);
if (address != 0) Agc::Command::CheckAddress(address, 8, __func__);
Agc::Command::CheckBits(address, 0xffffffffffffull, __func__);
auto* packet = Agc::Command::Allocate(buf, 4, __func__);
packet[0] = Agc::Command::Header(0x11u, 4, shader_type != 0 ? 2u : 0u);

View File

@ -13,8 +13,7 @@
extern "C" {
// unknown signature
APS5_EXPORT("zARR5aCmkoY", sceAgcDcbA_zARR5aCmkoY);
void* APS5_VABI sceAgcDcbA_zARR5aCmkoY(void) {
void* APS5_VABI sceAgcDcbAtomicGds_0900(void) {
NotImplemented_nid_no_patch(__func__);
return nullptr;
}
@ -35,8 +34,7 @@ std::uint32_t* APS5_VABI sceAgcDcbResetQueue(CommandBuffer* buf, std::uint32_t o
}
std::uint32_t* APS5_VABI sceAgcDcbClearState(CommandBuffer* buf, std::uint32_t command) {
Agc::Command::CheckBits(command, 0xfu, __func__);
return Agc::Command::Emit(buf, 0x12u, {command}, __func__);
return Agc::Command::Emit(buf, 0x12u, {command & 0xfu}, __func__);
}
uint32_t* APS5_VABI sceAgcDcbRewind(CommandBuffer* buf, uint32_t initial_state) {

View File

@ -36,7 +36,6 @@ std::uint32_t* APS5_VABI sceAgcDcbEventWrite(CommandBuffer* buf, std::uint8_t ev
Agc::Command::CheckAddress(guestAddress, 8, __func__);
return Agc::Command::Emit(buf, 0x46u, {0x100u | eventType, static_cast<std::uint32_t>(guestAddress), static_cast<std::uint32_t>(guestAddress >> 32u)}, __func__);
}
Agc::Command::Require(address == nullptr, __func__, "this event does not use an address");
const auto eventIndex = eventType == 7 || eventType == 15 || eventType == 16 ? 0x400u : 0u;
return Agc::Command::Emit(buf, 0x46u, {eventIndex | eventType}, __func__);
}

View File

@ -7,6 +7,8 @@
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
static constexpr int SCE_AGC_ERROR_INVALID_ARGUMENT = static_cast<int>(0x80890001);
extern "C" {
int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) {
@ -16,6 +18,7 @@ int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) {
}
int APS5_VABI sceAgcInit(std::uint32_t version) {
if (version >= 14) return SCE_AGC_ERROR_INVALID_ARGUMENT;
Agc::Command::GetRegisterDefaults(version, false, __func__);
Agc::Command::GetRegisterDefaults(version, true, __func__);
return 0;

View File

@ -29,7 +29,7 @@ std::uint32_t* APS5_VABI sceAgcDcbSetCxRegistersIndirect(CommandBuffer* buf, con
}
std::uint32_t APS5_VABI sceAgcDcbSetCxRegistersIndirectGetSize(std::uint32_t numRegs) {
Agc::Command::CheckBits(numRegs, 0x3fffu, __func__);
static_cast<void>(numRegs);
return 20;
}
@ -46,7 +46,7 @@ std::uint32_t* APS5_VABI sceAgcDcbSetShRegistersIndirect(CommandBuffer* buf, con
}
std::uint32_t APS5_VABI sceAgcDcbSetShRegistersIndirectGetSize(std::uint32_t numRegs) {
Agc::Command::CheckBits(numRegs, 0x3fffu, __func__);
static_cast<void>(numRegs);
return 20;
}
@ -63,7 +63,7 @@ std::uint32_t* APS5_VABI sceAgcDcbSetUcRegistersIndirect(CommandBuffer* buf, con
}
std::uint32_t APS5_VABI sceAgcDcbSetUcRegistersIndirectGetSize(std::uint32_t numRegs) {
Agc::Command::CheckBits(numRegs, 0x3fffu, __func__);
static_cast<void>(numRegs);
return 20;
}

View File

@ -1,26 +1,62 @@
#include "prx/libSceAgc/DcbState/include/Workload.hpp"
#include "prx/libSceAgc/Command/include/Packet.hpp"
#include "prx/libSceAgcDriver/Resource/include/Registration.hpp"
#include <cstdint>
#include <cstddef>
#include <cstring>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
constexpr std::uint32_t OpcodeNop = 0x10;
constexpr std::uint32_t ActivePacketWords = 18;
constexpr std::uint32_t CompletePacketWords = 12;
constexpr std::uint32_t MaxWorkloadId = 63;
constexpr std::uint32_t MaxActiveCount = 63;
uint32_t* NewPacket(CommandBuffer* buf, std::uint32_t words, const char* function) {
auto* packet = Agc::Command::Allocate(buf, words, function);
std::memset(packet, 0, words * sizeof(std::uint32_t));
packet[0] = Agc::Command::Header(OpcodeNop, words, 0);
return packet;
}
}
extern "C" {
uint32_t* APS5_VABI sceAgcDcbSetWorkloadComplete(CommandBuffer* buf, uint32_t stream_id, uint32_t workload_id) {
(void)buf;
(void)stream_id;
(void)workload_id;
NotImplemented_nid_no_patch(__func__);
return nullptr;
if (buf == nullptr || workload_id > MaxWorkloadId || !AgcDriverWorkloadStreamRegistered_nid_postfix(stream_id)) return nullptr;
const std::uint64_t clearMask = ~(std::uint64_t{1} << workload_id);
auto* packet = NewPacket(buf, CompletePacketWords, __func__);
packet[1] = stream_id;
packet[2] = workload_id;
packet[3] = static_cast<std::uint32_t>(clearMask);
packet[4] = static_cast<std::uint32_t>(clearMask >> 32);
return packet;
}
uint32_t* APS5_VABI sceAgcDcbSetWorkloadsActive(CommandBuffer* buf, uint32_t stream_id, const uint32_t* workload_ids, uint32_t workload_count) {
(void)buf;
(void)stream_id;
(void)workload_ids;
(void)workload_count;
if (buf == nullptr || workload_ids == nullptr || workload_count == 0 || workload_count > MaxActiveCount || !AgcDriverWorkloadStreamRegistered_nid_postfix(stream_id)) return nullptr;
std::uint64_t mask = 0;
for (std::uint32_t index = 0; index < workload_count; ++index) {
const auto id = workload_ids[index];
if (id > MaxWorkloadId) return nullptr;
const std::uint64_t bit = std::uint64_t{1} << id;
if ((mask & bit) != 0) return nullptr;
mask |= bit;
}
auto* packet = NewPacket(buf, ActivePacketWords, __func__);
packet[1] = stream_id;
packet[2] = static_cast<std::uint32_t>(mask);
packet[3] = static_cast<std::uint32_t>(mask >> 32);
return packet;
}
uint32_t* APS5_VABI sceAgcDcbSetWorkloadStreamInactive(CommandBuffer* buf, uint32_t streamId) {
if (buf == nullptr || !AgcDriverWorkloadStreamRegistered_nid_postfix(streamId)) return nullptr;
NotImplemented_nid_no_patch(__func__);
return nullptr;
}

View File

@ -0,0 +1,4 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_DEBUG_HPP
#define CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_DEBUG_HPP
#endif

View File

@ -0,0 +1,4 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_SEMAPHORE_HPP
#define CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_SEMAPHORE_HPP
#endif

View File

@ -0,0 +1,14 @@
#include "prx/libSceAgc/Misc/include/Debug.hpp"
#include <cstdint>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId) {
APS5_LOG_OUT("sceAgcDebugRaiseException exceptionId=0x%08x", static_cast<unsigned>(exceptionId));
return 0;
}
}

View File

@ -0,0 +1,61 @@
#include "prx/libSceAgc/Misc/include/Semaphore.hpp"
#include "prx/libSceAgc/Command/include/Packet.hpp"
#include <cstdint>
#include <cstddef>
#include <cstring>
#include <limits>
#include <mutex>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
constexpr std::uint64_t semaphoreMemoryAlignment = 0x4000u;
constexpr std::uint64_t semaphoreLabelBytes = 32u;
constexpr std::uint64_t semaphoreCounterBytes = 8u;
std::mutex semaphoreMutex;
std::uint8_t* semaphoreMemory = nullptr;
std::uint64_t semaphoreBytes = 0;
bool hasOnlyZeroLabelTails(const std::uint8_t* memory, std::uint64_t sizeInBytes) {
for (std::uint64_t label = 0; label < sizeInBytes; label += semaphoreLabelBytes) {
for (std::uint64_t byte = semaphoreCounterBytes; byte < semaphoreLabelBytes; ++byte) {
if (memory[label + byte] != 0) return false;
}
}
return true;
}
}
extern "C" {
int APS5_VABI sceAgcSetAmmSemaphoreMemory(void* memory, std::uint64_t sizeInBytes) {
const auto address = reinterpret_cast<std::uintptr_t>(memory);
std::lock_guard lock(semaphoreMutex);
Agc::Command::Require(semaphoreMemory == nullptr, __func__, "the AMM semaphore memory is already registered; the console's error is unknown");
Agc::Command::Require(memory != nullptr && sizeInBytes != 0, __func__, "null or empty AMM semaphore memory; the console's error is unknown");
Agc::Command::Require(((address | sizeInBytes) & (semaphoreMemoryAlignment - 1u)) == 0, __func__, "AMM semaphore memory or size is not 16 KiB aligned; the console's error is unknown");
Agc::Command::Require(sizeInBytes - 1u <= std::numeric_limits<std::uintptr_t>::max() - address, __func__, "AMM semaphore memory wraps the address space");
auto* labels = static_cast<std::uint8_t*>(memory);
Agc::Command::Require(hasOnlyZeroLabelTails(labels, sizeInBytes), __func__, "AMM semaphore labels hold data past their first 8 bytes; whether registration clears it is unknown");
for (std::uint64_t label = 0; label < sizeInBytes; label += semaphoreLabelBytes) {
std::memset(labels + label, 0, semaphoreCounterBytes);
}
semaphoreMemory = labels;
semaphoreBytes = sizeInBytes;
return 0;
}
int APS5_VABI sceAgcGetSemaphoreLabel(std::uint32_t index, void** label) {
std::lock_guard lock(semaphoreMutex);
Agc::Command::Require(semaphoreMemory != nullptr, __func__, "no AMM semaphore memory is registered; the console's error is unknown");
Agc::Command::Require(index < semaphoreBytes / semaphoreLabelBytes, __func__, "the semaphore label lies outside the AMM semaphore memory; the console's error is unknown");
Agc::Command::Require(label != nullptr, __func__, "null semaphore label output; the console's error is unknown");
*label = semaphoreMemory + static_cast<std::uint64_t>(index) * semaphoreLabelBytes;
return 0;
}
}

View File

@ -19,6 +19,12 @@ void PatchBranchTarget(std::uint32_t* cmd, std::uint32_t field, const volatile s
cmd[field + 2u] = (cmd[field + 2u] & ~0xfffffu) | sizeInDwords;
}
void PatchBranchTarget(std::uint32_t* cmd, std::uint32_t field, std::uint8_t cachePolicy, const volatile std::uint32_t* target, std::uint32_t sizeInDwords, const char* function) {
Agc::Command::CheckBits(cachePolicy, 3, function);
PatchBranchTarget(cmd, field, target, sizeInDwords, function);
cmd[field + 2u] = (cmd[field + 2u] & ~(3u << 28u)) | (static_cast<std::uint32_t>(cachePolicy) << 28u);
}
}
extern "C" {
@ -42,4 +48,14 @@ int APS5_VABI sceAgcBranchPatchSetElseTarget(std::uint32_t* cmd, const volatile
return 0;
}
int APS5_VABI sceAgcBranchPatchSetThenTarget_0300(std::uint32_t* cmd, std::uint8_t cachePolicy, const volatile std::uint32_t* target, std::uint32_t sizeInDwords) {
PatchBranchTarget(cmd, 8, cachePolicy, target, sizeInDwords, __func__);
return 0;
}
int APS5_VABI sceAgcBranchPatchSetElseTarget_0300(std::uint32_t* cmd, std::uint8_t cachePolicy, const volatile std::uint32_t* target, std::uint32_t sizeInDwords) {
PatchBranchTarget(cmd, 11, cachePolicy, target, sizeInDwords, __func__);
return 0;
}
}

View File

@ -19,11 +19,13 @@ constexpr std::uint32_t VGT_SHADER_STAGES_EN = 0x2D5u;
constexpr std::uint32_t VGT_PRIMITIVE_TYPE = 0x242u;
constexpr std::uint32_t GE_CNTL = 0x25Bu;
constexpr std::uint32_t GE_USER_VGPR1 = 0x25Cu;
constexpr std::uint32_t GE_USER_VGPR_EN = 0x262u;
constexpr std::uint32_t GE_PC_ALLOC = 0x260u;
constexpr std::uint32_t SPI_SHADER_PGM_RSRC4_GS = 0x081u;
constexpr std::uint32_t SPI_VS_OUT_CONFIG = 0x1B1u;
constexpr std::uint32_t SPI_SHADER_IDX_FORMAT = 0x1C2u;
constexpr std::uint32_t GE_MAX_OUTPUT_PER_SUBGROUP = 0x1FFu;
constexpr std::uint32_t PA_CL_VS_OUT_CNTL = 0x207u;
constexpr std::uint32_t VGT_GS_ONCHIP_CNTL = 0x291u;
@ -78,7 +80,7 @@ enum class PrimitiveType : std::uint32_t {
};
constexpr std::uint32_t VGT_SHADER_STAGES_GS_BIT = 0x20u;
constexpr std::uint32_t VGT_SHADER_STAGES_NGG_BIT = 0x04u;
constexpr std::uint32_t VGT_SHADER_STAGES_HS_BIT = 0x04u;
enum class AgcDirectResourceType : std::uint32_t {
GdsCounterRange = 0,

View File

@ -0,0 +1,39 @@
#include <cstdint>
#include <stdexcept>
#include <string>
#include <prx/libc/include/General.hpp>
#include "SceShaders.hpp"
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
namespace {
constexpr std::uint32_t IDX0_EXPORT_FORMAT_MASK = 0xFu;
constexpr std::uint32_t SPI_SHADER_2COMP = 2u;
constexpr std::uint32_t TwoComponentPayloadBytes = 8u;
}
extern "C" {
int APS5_VABI sceAgcGetGsPrimPayload(std::uint32_t* payload, const Shader* gs) {
if (payload == nullptr || gs == nullptr) {
throw std::runtime_error(std::string(__func__) + ": payload or gs is null");
}
if (gs->num_cx_registers != 0 && gs->cx_registers == nullptr) {
throw std::runtime_error(std::string(__func__) + ": gs->cx_registers is null but num_cx_registers != 0");
}
std::uint32_t bytes = 0;
for (std::uint32_t i = 0; i < gs->num_cx_registers; ++i) {
const ShaderRegister& reg = gs->cx_registers[i];
if (reg.offset == ShaderRegs::SPI_SHADER_IDX_FORMAT && (reg.value & IDX0_EXPORT_FORMAT_MASK) == SPI_SHADER_2COMP) {
bytes = TwoComponentPayloadBytes;
break;
}
}
*payload = bytes;
return 0;
}
}

View File

@ -53,10 +53,21 @@ std::uint32_t CreateInterpolantValueSplitF16(std::uint32_t psWord, const ShaderS
: CreateInterpolantValue(psWord, gsSemantic);
}
int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader* gs, const Shader* ps, CreateInterpolantValueFn createValue) {
std::uint32_t UpdateInterpolantValue(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
const std::uint32_t f16 = (psWord >> 20u) & 0x3u;
if (f16 != 0 && f16 != InterpolantF16HiOnly && ((psWord >> 28u) & 0x3u) != ((psWord >> 30u) & 0x3u)) {
throw std::runtime_error(std::string(__func__) + ": DEFAULT_VAL of an f16 input with different low and high defaults is unknown");
}
return CreateInterpolantValueSplitF16(psWord, gsSemantic);
}
int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader* gs, const Shader* ps, CreateInterpolantValueFn createValue, bool fillIdentityTail) {
if (regs == nullptr) {
throw std::runtime_error(std::string(fn) + ": regs is null");
}
if (ps == nullptr && !fillIdentityTail) {
throw std::runtime_error(std::string(fn) + ": ps is null");
}
if (ps != nullptr && ps->num_input_semantics > 32) {
throw std::runtime_error(std::string(fn) + ": input semantic count exceeds 32");
}
@ -66,13 +77,14 @@ int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader*
auto* output = regs;
regs = values.data();
if (ps == nullptr || ps->num_input_semantics == 0) {
FillIdentityInterpolants(regs, 0);
const std::uint32_t count = fillIdentityTail ? InterpolantRegisterCount : 0;
if (fillIdentityTail) FillIdentityInterpolants(regs, 0);
if (ps != nullptr) {
AgcDriverResolveShaderAbi_nid_postfix(ps, {regs, 32}, {});
AgcDriverResolveShaderAbi_nid_postfix(ps, {regs, count}, {});
if (gs != nullptr) AgcDriverResolveGraphicsAbi_nid_postfix(gs, ps, 0);
}
transaction.Commit();
std::copy(values.begin(), values.end(), output);
std::copy_n(values.begin(), count, output);
return 0;
}
@ -98,11 +110,12 @@ int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader*
SetInterpolantRegister(regs, i, createValue(ShaderSemanticWord(psSemantic), gsSemantic));
}
FillIdentityInterpolants(regs, ps->num_input_semantics);
AgcDriverResolveShaderAbi_nid_postfix(ps, {regs, 32}, {});
const std::uint32_t count = fillIdentityTail ? InterpolantRegisterCount : ps->num_input_semantics;
if (fillIdentityTail) FillIdentityInterpolants(regs, ps->num_input_semantics);
AgcDriverResolveShaderAbi_nid_postfix(ps, {regs, count}, {});
AgcDriverResolveGraphicsAbi_nid_postfix(gs, ps, 0);
transaction.Commit();
std::copy(values.begin(), values.end(), output);
std::copy_n(values.begin(), count, output);
return 0;
}
@ -110,14 +123,18 @@ int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader*
extern "C" {
APS5_EXPORT("HV4j+E0MBHE", sceAgcCreateInterpolantMapping);
int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValue);
int APS5_VABI sceAgcCreateInterpolantMapping_0100(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValue, true);
}
APS5_EXPORT("dbOlWdppb4o", sceAgcUnknownCreateInterpolantMapping);
int APS5_VABI sceAgcUnknownCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueSplitF16);
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueSplitF16, true);
}
APS5_EXPORT("vieBRwlh1Lw", sceAgcUnknown_vieBRwlh1Lw);
int APS5_VABI sceAgcUnknown_vieBRwlh1Lw(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
return CreateInterpolantMapping(__func__, regs, gs, ps, UpdateInterpolantValue, false);
}
}

View File

@ -7,7 +7,7 @@
#include <algorithm>
extern "C" int APS5_VABI sceAgcCreatePrimState(ShaderRegister*, ShaderRegister*, const Shader*, const Shader*, std::uint32_t);
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister*, const Shader*, const Shader*);
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_0100(ShaderRegister*, const Shader*, const Shader*);
extern "C" int APS5_VABI sceAgcLinkShaders(ShaderRegister* context, ShaderRegister* primitive,
const void* reserved, const Shader* vertex, const Shader* pixel, std::uint32_t primitiveType) {
@ -26,7 +26,11 @@ extern "C" int APS5_VABI sceAgcLinkShaders(ShaderRegister* context, ShaderRegist
std::array<ShaderRegister, 34> contextValues{};
std::array<ShaderRegister, 3> primitiveValues{};
sceAgcCreatePrimState(contextValues.data(), primitiveValues.data(), nullptr, vertex, primitiveType);
sceAgcCreateInterpolantMapping(contextValues.data() + 2, vertex, pixel);
sceAgcCreateInterpolantMapping_0100(contextValues.data() + 2, vertex, pixel);
if (pixel != nullptr) {
const std::array<const Shader*, 2> stages{vertex, pixel};
AgcDriverResolveGraphicsStagesAbi_nid_postfix(stages, contextValues, primitiveValues);
}
AgcDriverResolveGraphicsAbi_nid_postfix(vertex, pixel, primitiveType);
transaction.Commit();
std::copy(contextValues.begin(), contextValues.end(), context);

View File

@ -11,6 +11,18 @@
#include "prx/libSceAgc/Shader/include/ShaderUtils.hpp"
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
namespace {
void RequireSpecialOffset(const ShaderRegister& reg, std::uint32_t expected, const char* name) {
if (reg.offset != expected) {
char message[160];
std::snprintf(message, sizeof(message), "sceAgcCreatePrimState: %s special register at offset 0x%x, expected 0x%x", name, static_cast<unsigned>(reg.offset), static_cast<unsigned>(expected));
throw std::runtime_error(message);
}
}
}
extern "C" {
int APS5_VABI sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, const Shader* hs, const Shader* gs, std::uint32_t prim_type) {
@ -25,31 +37,34 @@ int APS5_VABI sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_
throw std::runtime_error(std::string(__func__) + ": invalid shader type or missing special registers");
}
(void)GraphicsPrimTypeToGsOut(prim_type);
const auto valid = [](const Shader* shader) { return shader->specials->vgt_shader_stages_en.offset == ShaderRegs::VGT_SHADER_STAGES_EN && shader->specials->vgt_gs_out_prim_type.offset == ShaderRegs::VGT_GS_OUT_PRIM_TYPE; };
if (!valid(gs) || (hs != nullptr && !valid(hs))) {
throw std::runtime_error(std::string(__func__) + ": invalid context register offsets");
}
if (gs->specials->ge_cntl.offset != ShaderRegs::GE_CNTL || gs->specials->ge_user_vgpr_en.offset != ShaderRegs::GE_USER_VGPR_EN || (hs != nullptr && hs->specials->ge_user_vgpr_en.offset != ShaderRegs::GE_USER_VGPR_EN)) {
throw std::runtime_error(std::string(__func__) + ": invalid user configuration register offsets");
}
RequireSpecialOffset(gs->specials->vgt_shader_stages_en, ShaderRegs::VGT_SHADER_STAGES_EN, "VGT_SHADER_STAGES_EN");
if (hs != nullptr) RequireSpecialOffset(hs->specials->vgt_shader_stages_en, ShaderRegs::VGT_SHADER_STAGES_EN, "VGT_SHADER_STAGES_EN");
RequireSpecialOffset(gs->specials->ge_cntl, ShaderRegs::GE_CNTL, "GE_CNTL");
std::array<ShaderRegister, 2> contextValues{gs->specials->vgt_shader_stages_en, gs->specials->vgt_gs_out_prim_type};
if ((contextValues[0].value & ShaderRegs::VGT_SHADER_STAGES_GS_BIT) == 0) {
contextValues[1] = {ShaderRegs::VGT_GS_OUT_PRIM_TYPE, GraphicsPrimTypeToGsOut(prim_type)};
}
if (hs != nullptr) {
contextValues[0].value |= hs->specials->vgt_shader_stages_en.value;
if ((contextValues[0].value & ShaderRegs::VGT_SHADER_STAGES_GS_BIT) == 0) contextValues[1] = hs->specials->vgt_gs_out_prim_type;
}
if ((contextValues[0].value & ShaderRegs::VGT_SHADER_STAGES_GS_BIT) != 0) {
RequireSpecialOffset(gs->specials->vgt_gs_out_prim_type, ShaderRegs::VGT_GS_OUT_PRIM_TYPE, "VGT_GS_OUT_PRIM_TYPE");
} else if (hs != nullptr) {
RequireSpecialOffset(hs->specials->vgt_gs_out_prim_type, ShaderRegs::VGT_GS_OUT_PRIM_TYPE, "VGT_GS_OUT_PRIM_TYPE");
contextValues[1] = hs->specials->vgt_gs_out_prim_type;
} else {
contextValues[1] = {ShaderRegs::VGT_GS_OUT_PRIM_TYPE, GraphicsPrimTypeToGsOut(prim_type)};
}
std::array<ShaderRegister, 3> primitiveValues{gs->specials->ge_cntl, hs != nullptr ? hs->specials->ge_user_vgpr_en : gs->specials->ge_user_vgpr_en, ShaderRegister{ShaderRegs::VGT_PRIMITIVE_TYPE, prim_type}};
const std::array<const Shader*, 2> stages{hs, gs};
AgcDriverResolveGraphicsStagesAbi_nid_postfix(std::span(stages).subspan(hs == nullptr ? 1u : 0u), contextValues, primitiveValues);
const bool patch = prim_type == static_cast<std::uint32_t>(ShaderRegs::PrimitiveType::Patch);
if (patch == ((contextValues[0].value & ShaderRegs::VGT_SHADER_STAGES_HS_BIT) != 0)) {
AgcDriverResolveGraphicsStagesAbi_nid_postfix(std::span(stages).subspan(hs == nullptr ? 1u : 0u), contextValues, primitiveValues);
}
if (cx_regs != nullptr) std::copy(contextValues.begin(), contextValues.end(), cx_regs);
if (uc_regs != nullptr) std::copy(primitiveValues.begin(), primitiveValues.end(), uc_regs);
return 0;
}
int APS5_VABI sceAgcUpdatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, std::uint32_t prim_type) {
if (cx_regs != nullptr && (cx_regs[0].value & (ShaderRegs::VGT_SHADER_STAGES_GS_BIT | ShaderRegs::VGT_SHADER_STAGES_NGG_BIT)) == 0) {
if (cx_regs != nullptr && (cx_regs[0].value & (ShaderRegs::VGT_SHADER_STAGES_GS_BIT | ShaderRegs::VGT_SHADER_STAGES_HS_BIT)) == 0) {
cx_regs[1].value &= ~0x7u;
cx_regs[1].value |= GraphicsPrimTypeToGsOut(prim_type);
}

View File

@ -15,21 +15,6 @@ int APS5_VABI sceAgcAcbSetMarkerSpan() {
return 0;
}
int APS5_VABI sceAgcAcbSetWorkloadComplete() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcAcbSetWorkloadStreamInactive() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcAcbSetWorkloadsActive() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcAcquireMemSetEngine() {
NotImplemented_nid_no_patch(__func__);
return 0;
@ -45,31 +30,11 @@ int APS5_VABI sceAgcDcbSetMarkerSpan() {
return 0;
}
int APS5_VABI sceAgcDcbSetWorkloadStreamInactive() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcDebugRaiseException() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcGetDefaultCxStateFlat() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcGetSemaphoreLabel() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcSetAmmSemaphoreMemory() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcSetSemaphoreMemory() {
NotImplemented_nid_no_patch(__func__);
return 0;
@ -80,16 +45,6 @@ int APS5_VABI sceAgcCbMemsetExclusive() {
return 0;
}
int APS5_VABI sceAgcBranchPatchSetThenTarget_0300() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcGetGsPrimPayload() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcSetShaderInstrumentation() {
NotImplemented_nid_no_patch(__func__);
return 0;
@ -100,15 +55,4 @@ int APS5_VABI sceAgcGetShaderInstrumentation() {
return 0;
}
int APS5_VABI sceAgcBranchPatchSetElseTarget_0300() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
APS5_EXPORT("vieBRwlh1Lw", sceAgcUnknown_vieBRwlh1Lw);
int APS5_VABI sceAgcUnknown_vieBRwlh1Lw(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
}

View File

@ -13,6 +13,8 @@ std::uint32_t APS5_VABI sceAgcCbBranchGetSize();
int APS5_VABI sceAgcBranchPatchSetCompareAddress(std::uint32_t*, const volatile std::uint64_t*);
int APS5_VABI sceAgcBranchPatchSetThenTarget(std::uint32_t*, const volatile std::uint32_t*, std::uint32_t);
int APS5_VABI sceAgcBranchPatchSetElseTarget(std::uint32_t*, const volatile std::uint32_t*, std::uint32_t);
int APS5_VABI sceAgcBranchPatchSetThenTarget_0300(std::uint32_t*, std::uint8_t, const volatile std::uint32_t*, std::uint32_t);
int APS5_VABI sceAgcBranchPatchSetElseTarget_0300(std::uint32_t*, std::uint8_t, const volatile std::uint32_t*, std::uint32_t);
}
namespace {
@ -107,6 +109,31 @@ void testTarget(TSetter setter, std::size_t field, std::uint32_t cachePolicyBits
check(storage.words == expected, name);
}
template <typename TSetter>
void testTargetWithCachePolicy(TSetter setter, std::size_t field, const char* name) {
Storage storage;
auto expected = storage.words;
expected[field] = 0x89abcdecu;
expected[field + 1] = 0x4567u;
expected[field + 2] = 0x30000004u;
check(setter(storage.packet, 3, targetAt(0x0000456789abcdecull), 4) == 0, name);
check(storage.words == expected, name);
expected[field] = 0x1000u;
expected[field + 1] = 0;
expected[field + 2] = 0xfffffu;
check(setter(storage.packet, 0, targetAt(0x1000u), 0xfffffu) == 0, name);
check(storage.words == expected, name);
expectFailure([&] { setter(storage.packet, 4, targetAt(0x2000u), 1); });
expectFailure([&] { setter(storage.packet, 1, nullptr, 1); });
expectFailure([&] { setter(storage.packet, 1, targetAt(0x1002u), 1); });
expectFailure([&] { setter(storage.packet, 1, targetAt(0x2000u), 0x100000u); });
expectFailure([&] { setter(nullptr, 1, targetAt(0x2000u), 1); });
storage.packet[0] = 0xc00b3f00u;
expected[0] = 0xc00b3f00u;
expectFailure([&] { setter(storage.packet, 1, targetAt(0x2000u), 1); });
check(storage.words == expected, name);
}
void testMalformedPackets() {
for (const auto header : {0xc0023f00u, 0xc00b3f00u, 0xc00c3f01u, 0xc00c2200u}) {
Storage storage;
@ -128,6 +155,8 @@ int main() {
testCompareAddress();
testTarget(sceAgcBranchPatchSetThenTarget, 8, 0x10000000u, "then target setter wrote the wrong words");
testTarget(sceAgcBranchPatchSetElseTarget, 11, 0x20000000u, "else target setter wrote the wrong words");
testTargetWithCachePolicy(sceAgcBranchPatchSetThenTarget_0300, 8, "3.00 then target setter wrote the wrong words");
testTargetWithCachePolicy(sceAgcBranchPatchSetElseTarget_0300, 11, "3.00 else target setter wrote the wrong words");
testMalformedPackets();
std::puts("AGC branch patch tests passed");
return 0;

View File

@ -10,9 +10,12 @@
#include <cstring>
#include <string>
extern "C" std::uint32_t* APS5_VABI sceAgcDcbEventWrite(CommandBuffer* buf, std::uint8_t eventType, const volatile void* address);
extern "C" std::uint64_t APS5_VABI sceAgcDcbEventWriteGetSize(std::uint8_t eventType);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbResetQueue(CommandBuffer* buf, std::uint32_t op, std::uint32_t state);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbClearState(CommandBuffer* buf, std::uint32_t command);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetFlip(CommandBuffer* buf, std::uint32_t handle, std::int32_t index, std::uint32_t mode, std::int64_t argument);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbWaitUntilSafeForRendering(CommandBuffer* buf, std::uint32_t handle, std::uint32_t index);
extern "C" int APS5_VABI sceAgcSuspendPoint();
extern "C" int APS5_VABI sceAgcInit(std::uint32_t version);
extern "C" void* APS5_VABI sceAgcGetRegisterDefaults();
@ -29,14 +32,28 @@ extern "C" std::uint32_t* APS5_VABI sceAgcCbSetShRegisterRangeDirect(CommandBuff
extern "C" std::uint32_t* APS5_VABI sceAgcDcbContextStateOp_0100(CommandBuffer* buf, std::uint32_t operation);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbPushMarker(CommandBuffer* buf, const char* str, std::uint32_t color);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbPopMarker(CommandBuffer* buf);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetWorkloadComplete(CommandBuffer* buf, std::uint32_t stream_id, std::uint32_t workload_id);
extern "C" int APS5_VABI sceAgcDriverRegisterWorkloadStream(std::uint32_t stream_id, const void* stream);
extern "C" int APS5_VABI sceAgcDriverUnregisterWorkloadStream(std::uint32_t stream_id);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetWorkloadsActive(CommandBuffer* buf, std::uint32_t stream_id, const std::uint32_t* workload_ids, std::uint32_t workload_count);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetWorkloadStreamInactive(CommandBuffer* buf, std::uint32_t streamId);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadsActive(CommandBuffer* buf, std::uint32_t streamId, const std::uint32_t* workloadIds, std::uint32_t workloadCount);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadComplete(CommandBuffer* buf, std::uint32_t streamId, std::uint32_t workloadId);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbSetWorkloadStreamInactive(CommandBuffer* buf, std::uint32_t streamId);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetMarker(CommandBuffer* buf, const char* str, std::uint32_t color);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbPushMarker(CommandBuffer* buf, const char* str, std::uint32_t color);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbPopMarker(CommandBuffer* buf);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbSetMarker(CommandBuffer* buf, const char* str, std::uint32_t color);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetIndexBuffer(CommandBuffer* buf, std::uint64_t indexAddress);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetBaseIndirectArgs(CommandBuffer* buf, std::uint32_t shaderType, const volatile void* indirectBaseAddr);
extern "C" std::uint32_t* APS5_VABI sceAgcSetNop(CommandBuffer* buf, std::uint32_t sizeDw);
extern "C" int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId);
extern "C" std::uint32_t* APS5_VABI sceAgcAcbAtomicGds_0900(CommandBuffer* buf, std::uint32_t control, std::uint32_t mode, std::uint32_t gdsOp, std::uint32_t src, std::uint16_t offset, std::uint16_t index, std::uint32_t mask, std::uint32_t data, std::uint64_t compareData, std::uint64_t extraData);
namespace {
constexpr int SCE_AGC_ERROR_INVALID_ARGUMENT = static_cast<int>(0x80890001);
void check(bool condition, const char* message) {
if (!condition) {
throw std::runtime_error(message);
@ -109,6 +126,21 @@ void testPackets() {
check(noDown.cursor_up == scratch.data() + 6, "allocation past the top of a buffer without a down cursor advanced its cursor");
}
void testNop() {
Storage storage;
storage.words.fill(0xdeadbeefu);
auto* single = sceAgcSetNop(&storage.buffer, 1);
auto* pair = sceAgcSetNop(&storage.buffer, 2);
auto* triple = sceAgcSetNop(&storage.buffer, 3);
const std::array<std::uint32_t, 7> expected{0xffff1000u, 0xc0001000u, 0, 0xc0011000u, 0, 0, 0xdeadbeefu};
check(single == storage.words.data() && pair == single + 1 && triple == pair + 2, "incorrect NOP placement");
check(std::equal(expected.begin(), expected.end(), storage.words.begin()), "incorrect NOP packet");
check(storage.buffer.cursor_up == storage.words.data() + 6, "incorrect NOP cursor advance");
expectFailure([&] { sceAgcSetNop(&storage.buffer, 0); });
expectFailure([&] { sceAgcSetNop(&storage.buffer, 0x4002u); });
check(storage.buffer.cursor_up == storage.words.data() + 6, "invalid NOP advanced the cursor");
}
void testClearState() {
Storage storage;
storage.words.fill(0xdeadbeefu);
@ -116,12 +148,14 @@ void testClearState() {
auto* packet = sceAgcDcbClearState(&storage.buffer, command);
check(packet == storage.words.data() + command * 2 && packet[0] == 0xc0001200u && packet[1] == command, "incorrect CLEAR_STATE packet");
}
check(storage.buffer.cursor_up == storage.words.data() + 32 && storage.words[32] == 0xdeadbeefu, "incorrect CLEAR_STATE cursor advance");
auto* maskedZero = sceAgcDcbClearState(&storage.buffer, 0x10u);
check(maskedZero == storage.words.data() + 32 && maskedZero[0] == 0xc0001200u && maskedZero[1] == 0, "CLEAR_STATE did not mask the command to four bits");
auto* maskedF = sceAgcDcbClearState(&storage.buffer, 0xffffffffu);
check(maskedF == storage.words.data() + 34 && maskedF[0] == 0xc0001200u && maskedF[1] == 0xfu, "CLEAR_STATE did not mask the command to four bits");
check(storage.buffer.cursor_up == storage.words.data() + 36 && storage.words[36] == 0xdeadbeefu, "incorrect CLEAR_STATE cursor advance");
const auto before = storage.words;
expectFailure([&] { sceAgcDcbClearState(&storage.buffer, 0x10u); });
expectFailure([&] { sceAgcDcbClearState(&storage.buffer, 0xffffffffu); });
expectFailure([] { sceAgcDcbClearState(nullptr, 0); });
check(storage.words == before && storage.buffer.cursor_up == storage.words.data() + 32, "invalid CLEAR_STATE modified the buffer");
check(storage.words == before && storage.buffer.cursor_up == storage.words.data() + 36, "invalid CLEAR_STATE modified the buffer");
}
struct ContextGrowth {
@ -186,6 +220,91 @@ void testMarkers() {
expectFailure([] { sceAgcAcbSetMarker(nullptr, "frame", 0); });
}
void testWorkloads() {
Storage dcb;
const std::uint32_t ids[2] = {3, 4};
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, ids, 2) == nullptr, "workloads active packet for an unregistered stream");
check(sceAgcDcbSetWorkloadComplete(&dcb.buffer, 1, 3) == nullptr, "workload complete packet for an unregistered stream");
check(dcb.buffer.cursor_up == dcb.words.data(), "unregistered stream advanced the cursor");
const std::uint32_t record[8] = {};
check(sceAgcDriverRegisterWorkloadStream(1, record) == 0, "workload stream registration failed");
const auto* active = sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, ids, 2);
check(active == dcb.words.data() && active[0] == Agc::Command::Header(0x10, 18, 0) && active[1] == 1 && active[2] == 0x18 && active[3] == 0, "workloads active packet");
for (std::uint32_t word = 4; word < 18; ++word) check(active[word] == 0, "workloads active packet tail is not zero");
const auto* complete = sceAgcDcbSetWorkloadComplete(&dcb.buffer, 1, 33);
check(complete == dcb.words.data() + 18 && complete[0] == Agc::Command::Header(0x10, 12, 0) && complete[1] == 1 && complete[2] == 33 && complete[3] == 0xffffffffu && complete[4] == 0xfffffffdu, "workload complete packet");
for (std::uint32_t word = 5; word < 12; ++word) check(complete[word] == 0, "workload complete packet tail is not zero");
check(dcb.buffer.cursor_up == dcb.words.data() + 30, "incorrect workload cursor advance");
const std::uint32_t duplicate[2] = {5, 5};
const std::uint32_t outOfRange[1] = {64};
const std::uint32_t top[1] = {63};
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, duplicate, 2) == nullptr, "duplicate workload ids accepted");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, outOfRange, 1) == nullptr, "workload id 64 accepted");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, top, 1) != nullptr, "workload id 63 rejected");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, ids, 0) == nullptr, "workload count 0 accepted");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 1, nullptr, 2) == nullptr, "null workload ids accepted");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 0, ids, 2) == nullptr, "stream id 0 accepted");
check(sceAgcDcbSetWorkloadsActive(&dcb.buffer, 32, ids, 2) == nullptr, "stream id 32 accepted");
check(sceAgcDcbSetWorkloadComplete(&dcb.buffer, 1, 64) == nullptr, "workload complete id 64 accepted");
check(sceAgcDcbSetWorkloadsActive(nullptr, 1, ids, 2) == nullptr, "null command buffer accepted");
check(sceAgcDcbSetWorkloadComplete(nullptr, 1, 3) == nullptr, "null command buffer accepted for complete");
check(sceAgcDriverUnregisterWorkloadStream(1) == 0, "workload stream unregistration failed");
check(sceAgcDcbSetWorkloadComplete(&dcb.buffer, 1, 3) == nullptr, "workload complete packet after unregistration");
}
void testWorkloadStreams() {
struct Vector {
std::uint32_t streamId;
std::uintptr_t workloadIds;
std::uint32_t workloadCount;
std::uint32_t workloadId;
};
const std::array<Vector, 3> vectors{{
{0x11111111u, 0x22222222u, 0x33333333u, 0x22222222u},
{1, 2, 3, 2},
{0x22222222u, static_cast<std::uintptr_t>(0x3333333344444444ull), 0, 0x44444444u}}};
for (const auto& vector : vectors) {
Storage storage;
storage.words.fill(0xdeadbeefu);
const auto before = storage.words;
const auto* ids = reinterpret_cast<const std::uint32_t*>(vector.workloadIds);
check(sceAgcDcbSetWorkloadsActive(&storage.buffer, vector.streamId, ids, vector.workloadCount) == nullptr, "DCB workloads active returned a packet for an unregistered stream");
check(sceAgcDcbSetWorkloadComplete(&storage.buffer, vector.streamId, vector.workloadId) == nullptr, "DCB workload complete returned a packet for an unregistered stream");
check(sceAgcDcbSetWorkloadStreamInactive(&storage.buffer, vector.streamId) == nullptr, "DCB workload stream inactive returned a packet for an unregistered stream");
check(sceAgcAcbSetWorkloadsActive(&storage.buffer, vector.streamId, ids, vector.workloadCount) == nullptr, "ACB workloads active returned a packet for an unregistered stream");
check(sceAgcAcbSetWorkloadComplete(&storage.buffer, vector.streamId, vector.workloadId) == nullptr, "ACB workload complete returned a packet for an unregistered stream");
check(sceAgcAcbSetWorkloadStreamInactive(&storage.buffer, vector.streamId) == nullptr, "ACB workload stream inactive returned a packet for an unregistered stream");
check(storage.words == before && storage.buffer.cursor_up == storage.words.data(), "a workload call for an unregistered stream wrote to the buffer");
}
const std::uint32_t ids[2] = {3, 4};
Storage exhausted;
exhausted.buffer.cursor_down = exhausted.words.data() + 3;
const auto before = exhausted.words;
check(sceAgcDcbSetWorkloadStreamInactive(&exhausted.buffer, 1) == nullptr && sceAgcAcbSetWorkloadsActive(&exhausted.buffer, 1, ids, 2) == nullptr &&
sceAgcAcbSetWorkloadComplete(&exhausted.buffer, 1, 3) == nullptr && sceAgcAcbSetWorkloadStreamInactive(&exhausted.buffer, 1) == nullptr,
"a workload call for an unregistered stream on an exhausted buffer returned a packet");
check(exhausted.words == before && exhausted.buffer.cursor_up == exhausted.words.data(), "a workload call for an unregistered stream modified an exhausted buffer");
check(sceAgcDcbSetWorkloadStreamInactive(nullptr, 1) == nullptr && sceAgcAcbSetWorkloadsActive(nullptr, 1, ids, 2) == nullptr &&
sceAgcAcbSetWorkloadComplete(nullptr, 1, 3) == nullptr && sceAgcAcbSetWorkloadStreamInactive(nullptr, 1) == nullptr,
"a workload call with a null command buffer returned a packet");
const std::uint32_t record[8] = {};
check(sceAgcDriverRegisterWorkloadStream(1, record) == 0, "workload stream registration failed");
Storage registered;
registered.words.fill(0xdeadbeefu);
const auto untouched = registered.words;
expectFailure([&] { sceAgcDcbSetWorkloadStreamInactive(&registered.buffer, 1); });
expectFailure([&] { sceAgcAcbSetWorkloadsActive(&registered.buffer, 1, ids, 2); });
expectFailure([&] { sceAgcAcbSetWorkloadComplete(&registered.buffer, 1, 3); });
expectFailure([&] { sceAgcAcbSetWorkloadStreamInactive(&registered.buffer, 1); });
check(registered.words == untouched && registered.buffer.cursor_up == registered.words.data(), "a workload call that threw modified the buffer");
check(sceAgcDcbSetWorkloadStreamInactive(nullptr, 1) == nullptr && sceAgcAcbSetWorkloadsActive(nullptr, 1, ids, 2) == nullptr &&
sceAgcAcbSetWorkloadComplete(nullptr, 1, 3) == nullptr && sceAgcAcbSetWorkloadStreamInactive(nullptr, 1) == nullptr,
"a workload call with a null command buffer for a registered stream returned a packet");
check(sceAgcDriverUnregisterWorkloadStream(1) == 0, "workload stream unregistration failed");
}
void testIndexBuffer() {
Storage storage;
alignas(4) std::uint16_t indices[2]{};
@ -205,6 +324,19 @@ void testIndexBuffer() {
throw std::runtime_error("misaligned index buffer was accepted");
}
void testIndirectBase() {
Storage storage;
alignas(8) std::uint32_t arguments[4]{};
const auto address = reinterpret_cast<std::uintptr_t>(arguments);
const auto* bound = sceAgcDcbSetBaseIndirectArgs(&storage.buffer, 0, arguments);
check(bound[1] == 1 && bound[2] == static_cast<std::uint32_t>(address) && bound[3] == static_cast<std::uint32_t>(address >> 32u), "indirect base address mismatch");
const auto* cleared = sceAgcDcbSetBaseIndirectArgs(&storage.buffer, 1, nullptr);
check(cleared == bound + 4 && (cleared[0] & 2u) != 0 && cleared[1] == 1 && cleared[2] == 0 && cleared[3] == 0, "indirect base was not cleared");
const auto before = storage.words;
expectFailure([&] { sceAgcDcbSetBaseIndirectArgs(&storage.buffer, 0, reinterpret_cast<const volatile void*>(address + 4)); });
check(storage.words == before, "misaligned indirect base modified packet memory");
}
void testContextState() {
const std::array<std::array<std::uint32_t, 6>, 4> sizes{{{5}, {5, 8, 9, 3, 2}, {3, 5, 8, 9, 2}, {5, 8, 9, 3, 2, 5}}};
const std::array<std::array<std::uint32_t, 4>, 4> reservations{{{5}, {22, 3, 2}, {3, 22, 2}, {22, 3, 2, 5}}};
@ -283,6 +415,17 @@ void testFlip() {
exhausted.buffer.cursor_down = exhausted.words.data() + 5;
expectFailure([&] { sceAgcDcbSetFlip(&exhausted.buffer, 1, 0, 1, 0); });
check(exhausted.buffer.cursor_up == exhausted.words.data(), "failed flip allocation advanced cursor");
Storage acb;
acb.words.fill(0xdeadbeefu);
auto* wait = sceAgcAcbWaitUntilSafeForRendering(&acb.buffer, 0xfedcba98u, 2);
const std::array<std::uint32_t, 4> expectedWait{0xc0021018u, 0xfedcba98u, 2, 0};
check(wait == acb.words.data() && std::equal(expectedWait.begin(), expectedWait.end(), wait), "compute rendering wait packet mismatch");
check(acb.buffer.cursor_up == wait + 4 && wait[4] == 0xdeadbeefu, "compute rendering wait overran allocation");
expectFailure([] { sceAgcAcbWaitUntilSafeForRendering(nullptr, 1, 0); });
Storage full;
full.buffer.cursor_down = full.words.data() + 3;
expectFailure([&] { sceAgcAcbWaitUntilSafeForRendering(&full.buffer, 1, 0); });
check(full.buffer.cursor_up == full.words.data(), "failed compute rendering wait advanced cursor");
check(sceAgcSuspendPoint() == 0, "empty suspend failed");
}
@ -371,6 +514,111 @@ void testMemory() {
check(storage.words == beforeMask, "invalid mask patch modified packet memory");
}
struct AtomicGdsAllocation {
Storage storage;
std::uint32_t capacity = 15;
std::uint32_t calls = 0;
bool accepted = true;
};
bool APS5_VABI growAtomicGds(CommandBuffer* buffer, std::uint32_t count, void* userData) {
auto& allocation = *static_cast<AtomicGdsAllocation*>(userData);
check(count == 15, "atomic GDS allocation omitted packet or reserved words");
++allocation.calls;
if (!allocation.accepted) return false;
buffer->bottom = allocation.storage.words.data();
buffer->top = buffer->bottom + allocation.capacity;
buffer->cursor_up = buffer->bottom;
buffer->cursor_down = buffer->top;
return true;
}
void testAtomicGds() {
Storage storage;
storage.words.fill(0xdeadbeefu);
storage.buffer.cursor_up += 2;
auto* packet = sceAgcAcbAtomicGds_0900(&storage.buffer, 0xffffffffu, 1, 0xffffffffu, 0xffffffffu,
0xabcd, 0xfedc, 0x12345678u, 0x87654321u, 0xfedcba9876543210ull, 0x0123456789abcdefull);
const std::array<std::uint32_t, 11> expected{
0xc0091d00u, 0x001500ffu, 0x13fu, 0xabcdu, 0xfedcu, 0x00340078u,
0x87654321u, 0x76543210u, 0xfedcba98u, 0x89abcdefu, 0x01234567u};
check(packet == storage.words.data() + 2, "atomic GDS returned the wrong packet address");
check(std::equal(expected.begin(), expected.end(), packet), "atomic GDS packet or guest ABI mismatch");
check(storage.buffer.cursor_up == packet + expected.size(), "atomic GDS did not advance by eleven words");
check(storage.words[0] == 0xdeadbeefu && storage.words[1] == 0xdeadbeefu &&
std::all_of(storage.words.begin() + 13, storage.words.end(), [](auto word) { return word == 0xdeadbeefu; }),
"atomic GDS wrote outside its packet");
const std::array<std::array<std::uint32_t, 3>, 9> controls{{
{0, 0, 0}, {0, 1, 0x00020000u}, {0, 2, 0}, {0, 0xffffffffu, 0},
{0x20u, 1, 0x00040020u}, {0x40u, 1, 0x00120040u},
{0x200u, 1, 0x00030000u}, {0xfffffd00u, 0, 0}, {0xffu, 1, 0x001400ffu}}};
for (const auto& entry : controls) {
Storage controlStorage;
auto* controlPacket = sceAgcAcbAtomicGds_0900(&controlStorage.buffer, entry[0], entry[1],
0xfffffffeu, 0xffffffc0u, 0, 0, 0xff00ff00u, 0, 0, 0);
std::array<std::uint32_t, 11> controlExpected{};
controlExpected[0] = 0xc0091d00u;
controlExpected[1] = entry[2];
check(std::equal(controlExpected.begin(), controlExpected.end(), controlPacket), "atomic GDS control or field masking mismatch");
}
auto emit = [](CommandBuffer* buffer) {
return sceAgcAcbAtomicGds_0900(buffer, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
};
Storage exact;
exact.buffer.cursor_down = exact.words.data() + 15;
exact.buffer.reserved_dw = 4;
check(emit(&exact.buffer) == exact.words.data() && exact.buffer.cursor_up == exact.words.data() + 11,
"atomic GDS rejected an exact fit with reserved space");
const auto exactBefore = exact.words;
expectFailure([&] { emit(&exact.buffer); });
check(exact.words == exactBefore && exact.buffer.cursor_up == exact.words.data() + 11,
"atomic GDS overwrote reserved space");
Storage exhausted;
exhausted.buffer.cursor_down = exhausted.words.data() + 10;
const auto before = exhausted.words;
expectFailure([&] { emit(&exhausted.buffer); });
check(exhausted.words == before && exhausted.buffer.cursor_up == exhausted.words.data(),
"failed atomic GDS allocation modified the buffer");
expectFailure([&] { emit(nullptr); });
Storage noDown;
noDown.buffer.top = noDown.words.data() + 11;
noDown.buffer.cursor_down = nullptr;
check(emit(&noDown.buffer) == noDown.words.data() && noDown.buffer.cursor_up == noDown.buffer.top,
"atomic GDS did not honor a buffer with no down cursor");
AtomicGdsAllocation allocation;
CommandBuffer growing{nullptr, nullptr, nullptr, nullptr, growAtomicGds, &allocation, 4};
check(emit(&growing) == allocation.storage.words.data() && allocation.calls == 1 &&
growing.cursor_up == allocation.storage.words.data() + 11, "atomic GDS did not use the guest allocation callback");
const std::array<std::uint32_t, 11> zeroPacket{0xc0091d00u};
check(std::equal(zeroPacket.begin(), zeroPacket.end(), allocation.storage.words.begin()),
"atomic GDS callback allocation produced the wrong packet");
for (const bool accepted : {false, true}) {
AtomicGdsAllocation failure;
failure.accepted = accepted;
failure.capacity = 14;
const auto failureBefore = failure.storage.words;
CommandBuffer failed{nullptr, nullptr, nullptr, nullptr, growAtomicGds, &failure, 4};
expectFailure([&] { emit(&failed); });
check(failure.calls == 1 && failure.storage.words == failureBefore &&
failed.cursor_up == (accepted ? failure.storage.words.data() : nullptr),
"atomic GDS wrote a packet after failed or insufficient allocation");
}
}
void testDebugRaiseException() {
int result = -1;
try {
result = sceAgcDebugRaiseException(0x1234abcdu);
} catch (const std::exception& error) {
throw std::runtime_error(std::string("debug exception stopped the caller: ") + error.what());
}
check(result == 0, "debug exception did not return 0");
}
void testDefaults() {
std::uint32_t state = 0x12345678;
check(sceAgcInit_0090(&state, 8) == 0 && state == 0x12345678, "AGC initialization failed or modified caller state");
@ -378,8 +626,10 @@ void testDefaults() {
expectFailure([] { sceAgcInit_0090(nullptr, 8); });
expectFailure([&] { sceAgcInit_0090(&state, 14); });
check(sceAgcInit(8) == 0, "AGC version initialization failed");
expectFailure([] { sceAgcInit(14); });
expectFailure([] { sceAgcInit(0xffffffffu); });
check(sceAgcInit(13) == 0, "AGC version 13 initialization failed");
check(sceAgcInit(14) == SCE_AGC_ERROR_INVALID_ARGUMENT, "unsupported AGC version did not return invalid argument");
check(sceAgcInit(0xffffffffu) == SCE_AGC_ERROR_INVALID_ARGUMENT, "maximum AGC version did not return invalid argument");
check(sceAgcInit(0xffffc278u) == SCE_AGC_ERROR_INVALID_ARGUMENT, "pointer-valued AGC argument did not return invalid argument");
for (std::uint32_t version = 0; version < 14; ++version) {
for (const bool internal : {false, true}) {
auto* first = Agc::Command::GetRegisterDefaults(version, internal, __func__);
@ -393,6 +643,47 @@ void testDefaults() {
expectFailure([] { Agc::Command::GetRegisterDefaults(0xffffffffu, true, __func__); });
}
void testEventWrite() {
Storage storage;
const auto* samplePacket = sceAgcDcbEventWrite(&storage.buffer, 0x38, reinterpret_cast<const void*>(0x1000));
check(samplePacket == storage.words.data(), "incorrect event 0x38 return pointer");
check(storage.words[0] == 0xc0024600u, "incorrect event 0x38 packet header");
check(storage.words[1] == (0x100u | 0x38u), "incorrect event 0x38 first payload word");
check(storage.words[2] == 0x1000u, "incorrect event 0x38 low address word");
check(storage.words[3] == 0u, "incorrect event 0x38 high address word");
check(sceAgcDcbEventWriteGetSize(0x38) == 16, "incorrect event 0x38 size");
check(sceAgcDcbEventWriteGetSize(0x39) == 16, "incorrect event 0x39 size");
Storage sample39;
sceAgcDcbEventWrite(&sample39.buffer, 0x39, reinterpret_cast<const void*>(0x2008));
check(sample39.words[0] == 0xc0024600u && sample39.words[1] == (0x100u | 0x39u) && sample39.words[2] == 0x2008u && sample39.words[3] == 0u, "incorrect event 0x39 packet");
expectFailure([&] { sceAgcDcbEventWrite(&storage.buffer, 0x38, reinterpret_cast<const void*>(0x1001)); });
expectFailure([&] { sceAgcDcbEventWrite(&storage.buffer, 0x40, nullptr); });
Storage partialFlush;
sceAgcDcbEventWrite(&partialFlush.buffer, 7, nullptr);
check(partialFlush.words[0] == 0xc0004600u && partialFlush.words[1] == 0x407u, "incorrect event 7 partial flush packet");
check(sceAgcDcbEventWriteGetSize(7) == 8, "incorrect event 7 size");
Storage partialFlush15;
sceAgcDcbEventWrite(&partialFlush15.buffer, 15, nullptr);
check(partialFlush15.words[0] == 0xc0004600u && partialFlush15.words[1] == 0x40fu, "incorrect event 15 partial flush packet");
Storage partialFlush16;
sceAgcDcbEventWrite(&partialFlush16.buffer, 16, nullptr);
check(partialFlush16.words[0] == 0xc0004600u && partialFlush16.words[1] == 0x410u, "incorrect event 16 partial flush packet");
Storage cacheFlushNull;
sceAgcDcbEventWrite(&cacheFlushNull.buffer, 0x16, nullptr);
check(cacheFlushNull.words[0] == 0xc0004600u && cacheFlushNull.words[1] == 0x16u, "incorrect event 0x16 null address packet");
check(sceAgcDcbEventWriteGetSize(0x16) == 8, "incorrect event 0x16 size");
Storage cacheFlushWithAddress;
sceAgcDcbEventWrite(&cacheFlushWithAddress.buffer, 0x16, reinterpret_cast<const void*>(0x2d2a10000ull));
check(cacheFlushWithAddress.words[0] == 0xc0004600u && cacheFlushWithAddress.words[1] == 0x16u, "incorrect event 0x16 with address packet");
}
}
int main(int argc, char** argv) {
@ -404,16 +695,23 @@ int main(int argc, char** argv) {
return 0;
}
testPackets();
testEventWrite();
testNop();
testClearState();
testIndexedIndirectDraws();
testMarkers();
testWorkloads();
testWorkloadStreams();
testIndexBuffer();
testIndirectBase();
testContextState();
testFlip();
testRegisters();
testRegisterRange();
testPacketPayloadAddress();
testMemory();
testAtomicGds();
testDebugRaiseException();
testDefaults();
LibcRunShutdown_nid_postfix();
std::puts("AGC command tests passed");

View File

@ -0,0 +1,119 @@
#include "SceShaders.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
#include <array>
#include <cstdint>
#include <cstdio>
#include <stdexcept>
#include <vector>
extern "C" int APS5_VABI sceAgcGetGsPrimPayload(std::uint32_t* payload, const Shader* gs);
namespace {
constexpr std::uint32_t Sentinel = 0xccccccccu;
void check(bool condition, const char* message) {
if (!condition) throw std::runtime_error(message);
}
template <typename TAction>
void expectFailure(TAction action, const char* message) {
try {
action();
} catch (const std::exception& error) {
check(error.what()[0] != '\0', "empty exception message");
return;
}
throw std::runtime_error(message);
}
Shader makeGs(std::vector<ShaderRegister>& cx) {
Shader gs{};
gs.cx_registers = cx.empty() ? nullptr : cx.data();
gs.num_cx_registers = static_cast<std::uint8_t>(cx.size());
return gs;
}
void expectPayload(const Shader& gs, std::uint32_t expected, const char* message) {
std::array<std::uint32_t, 2> out{Sentinel, Sentinel};
check(sceAgcGetGsPrimPayload(out.data(), &gs) == 0, message);
check(out[0] == expected, message);
check(out[1] == Sentinel, "the payload write went past four bytes");
}
void testNoRegisters() {
std::vector<ShaderRegister> cx;
expectPayload(makeGs(cx), 0, "a shader without context registers reported a payload");
}
void testTwoComponentIndexFormat() {
std::vector<ShaderRegister> cx{{ShaderRegs::SPI_SHADER_IDX_FORMAT, 2u}};
expectPayload(makeGs(cx), 8, "a two-component index export did not report 8 bytes");
}
void testOnlyTheLowNibbleCounts() {
std::vector<ShaderRegister> high{{ShaderRegs::SPI_SHADER_IDX_FORMAT, 0xfffffff2u}};
expectPayload(makeGs(high), 8, "bits above IDX0_EXPORT_FORMAT changed the payload");
for (const std::uint32_t format : {0u, 1u, 3u, 4u, 0x20u}) {
std::vector<ShaderRegister> cx{{ShaderRegs::SPI_SHADER_IDX_FORMAT, format}};
expectPayload(makeGs(cx), 0, "an index export format other than two components reported a payload");
}
}
void testOtherRegistersAreIgnored() {
std::vector<ShaderRegister> cx{{ShaderRegs::SPI_VS_OUT_CONFIG, 2u}, {ShaderRegs::GE_MAX_OUTPUT_PER_SUBGROUP, 2u}};
expectPayload(makeGs(cx), 0, "a register other than SPI_SHADER_IDX_FORMAT reported a payload");
}
void testSearchContinuesPastAMismatch() {
std::vector<ShaderRegister> cx{
{ShaderRegs::SPI_VS_OUT_CONFIG, 0u},
{ShaderRegs::SPI_SHADER_IDX_FORMAT, 4u},
{ShaderRegs::SPI_SHADER_IDX_FORMAT, 2u},
};
expectPayload(makeGs(cx), 8, "a non-matching SPI_SHADER_IDX_FORMAT entry stopped the search");
}
void testCountBoundsTheSearch() {
std::vector<ShaderRegister> cx{{ShaderRegs::SPI_VS_OUT_CONFIG, 0u}, {ShaderRegs::SPI_SHADER_IDX_FORMAT, 2u}};
Shader gs = makeGs(cx);
gs.num_cx_registers = 1;
expectPayload(gs, 0, "an entry past num_cx_registers was read");
}
void testRejections() {
std::vector<ShaderRegister> cx{{ShaderRegs::SPI_SHADER_IDX_FORMAT, 2u}};
const Shader gs = makeGs(cx);
std::uint32_t out = Sentinel;
expectFailure([&] { sceAgcGetGsPrimPayload(nullptr, &gs); }, "a null payload pointer was accepted");
expectFailure([&] { sceAgcGetGsPrimPayload(&out, nullptr); }, "a null shader was accepted");
Shader missing{};
missing.num_cx_registers = 1;
expectFailure([&] { sceAgcGetGsPrimPayload(&out, &missing); }, "a register count without a register array was accepted");
check(out == Sentinel, "a rejected call wrote the payload");
}
}
int main() {
try {
testNoRegisters();
testTwoComponentIndexFormat();
testOnlyTheLowNibbleCounts();
testOtherRegistersAreIgnored();
testSearchContinuesPastAMismatch();
testCountBoundsTheSearch();
testRejections();
LibcRunShutdown_nid_postfix();
std::puts("AGC GS primitive payload tests passed");
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
try { LibcRunShutdown_nid_postfix(); }
catch (const std::exception& shutdown) { std::fprintf(stderr, "shutdown: %s\n", shutdown.what()); }
return 1;
}
}

View File

@ -11,14 +11,16 @@
#include <stdexcept>
#include <span>
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps);
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_0100(ShaderRegister* regs, const Shader* gs, const Shader* ps);
extern "C" int APS5_VABI sceAgcUnknownCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps);
extern "C" int APS5_VABI sceAgcUnknown_vieBRwlh1Lw(ShaderRegister* regs, const Shader* gs, const Shader* ps);
namespace {
using Registers = std::array<ShaderRegister, 32>;
const Shader* mappedPixel = nullptr;
Registers preparedMapping{};
std::size_t preparedCount = 0;
unsigned mappings = 0;
unsigned links = 0;
@ -65,6 +67,11 @@ void testIdentity() {
regs = filled();
check(sceAgcUnknownCreateInterpolantMapping(regs.data(), nullptr, &ps) == 0, "mapping without inputs failed");
checkIdentity(regs, 0, "mapping without inputs is not the identity");
regs = filled();
check(sceAgcUnknown_vieBRwlh1Lw(regs.data(), nullptr, &ps) == 0, "update without inputs failed");
check(preparedCount == 0u, "update without inputs prepared registers");
const auto untouched = filled();
check(std::memcmp(regs.data(), untouched.data(), sizeof(regs)) == 0, "update without inputs wrote registers");
}
void testMapping() {
@ -99,13 +106,67 @@ void testMapping() {
check(split[4].value == 0x03180002u, "full f16 interpolant mapping changed");
checkIdentity(split, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
auto update = filled();
const auto untouched = filled();
const std::size_t written = inputs.size() * sizeof(ShaderRegister);
check(sceAgcUnknown_vieBRwlh1Lw(update.data(), &gs, &ps) == 0, "update mapping failed");
check(preparedCount == inputs.size(), "update prepared registers past its inputs");
check(std::memcmp(update.data(), preparedMapping.data(), written) == 0, "prepared update differs from published registers");
check(std::memcmp(update.data(), split.data(), written) == 0, "update mapping differs from the split f16 mapping");
check(std::memcmp(update.data() + inputs.size(), untouched.data(), sizeof(update) - written) == 0, "update wrote past its inputs");
auto regular = filled();
check(sceAgcCreateInterpolantMapping(regular.data(), &gs, &ps) == 0, "mapping failed");
check(sceAgcCreateInterpolantMapping_0100(regular.data(), &gs, &ps) == 0, "mapping failed");
check(std::memcmp(regular.data(), preparedMapping.data(), sizeof(regular)) == 0, "prepared mapping differs from published registers");
check(regular[3].value == split[3].value && regular[4].value == split[4].value, "mappings differ outside the high f16 half mode");
checkIdentity(regular, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
}
void testUpdateMapping() {
std::array<ShaderSemantic, 4> inputs{semantic(1, 0, 0), semantic(2, 0, 1), semantic(3, 0, 2), semantic(4, 0, 3)};
inputs[0].is_custom = 1;
inputs[0].default_value = 2;
inputs[1].default_value = 1;
inputs[1].default_value_hi = 1;
inputs[2].default_value_hi = 2;
inputs[3].is_custom = 1;
inputs[3].default_value = 3;
inputs[3].default_value_hi = 3;
std::array<ShaderSemantic, 3> outputs{semantic(1, 5, 0), semantic(2, 7, 1), semantic(4, 9, 3)};
Shader gs{};
gs.output_semantics = outputs.data();
gs.num_output_semantics = static_cast<std::uint16_t>(outputs.size());
Shader ps{};
ps.input_semantics = inputs.data();
ps.num_input_semantics = static_cast<std::uint32_t>(inputs.size());
auto update = filled();
const auto untouched = filled();
check(sceAgcUnknown_vieBRwlh1Lw(update.data(), &gs, &ps) == 0, "update mapping failed");
check(update[0].value == 0x00000625u, "custom interpolant update changed");
check(update[1].value == 0x01380107u, "low f16 half update changed");
check(update[2].value == 0x02480220u, "unmatched high f16 half update changed");
check(update[3].value == 0x03680709u, "full f16 interpolant update changed");
for (std::uint32_t i = 0; i < inputs.size(); ++i) {
check(update[i].offset == ShaderRegs::SPI_PS_INPUT_CNTL_0 + i, "updated register offset changed");
}
const std::size_t written = inputs.size() * sizeof(ShaderRegister);
check(std::memcmp(update.data() + inputs.size(), untouched.data(), sizeof(update) - written) == 0, "update wrote past its inputs");
auto create = filled();
check(sceAgcUnknownCreateInterpolantMapping(create.data(), &gs, &ps) == 0, "split f16 mapping failed");
check(std::memcmp(create.data(), update.data(), written) == 0, "update differs from the split f16 mapping");
checkIdentity(create, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
for (const std::uint32_t index : {1u, 3u}) {
inputs[index].default_value = 0;
update = filled();
expectFailure([&] { sceAgcUnknown_vieBRwlh1Lw(update.data(), &gs, &ps); });
check(std::memcmp(update.data(), untouched.data(), sizeof(update)) == 0, "rejected update wrote registers");
inputs[index].default_value = inputs[index].default_value_hi;
}
}
void testRejections() {
std::array<ShaderSemantic, 33> inputs{};
Shader gs{};
@ -115,20 +176,25 @@ void testRejections() {
std::array<ShaderRegister, 64> regs{};
std::memset(regs.data(), 0xcc, sizeof(regs));
const auto saved = regs;
expectFailure([&] { sceAgcCreateInterpolantMapping(regs.data(), &gs, &ps); });
expectFailure([&] { sceAgcCreateInterpolantMapping_0100(regs.data(), &gs, &ps); });
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(regs.data(), &gs, &ps); });
expectFailure([&] { sceAgcUnknown_vieBRwlh1Lw(regs.data(), &gs, &ps); });
check(std::memcmp(regs.data(), saved.data(), sizeof(regs)) == 0, "rejected mapping wrote registers");
ps.num_input_semantics = 1;
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(regs.data(), nullptr, &ps); });
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(nullptr, &gs, &ps); });
expectFailure([&] { sceAgcUnknown_vieBRwlh1Lw(regs.data(), nullptr, &ps); });
expectFailure([&] { sceAgcUnknown_vieBRwlh1Lw(nullptr, &gs, &ps); });
expectFailure([&] { sceAgcUnknown_vieBRwlh1Lw(regs.data(), &gs, nullptr); });
}
}
extern "C" void AgcDriverResolveShaderAbi_nid_postfix(const Shader* shader, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive) {
check(shader != nullptr && context.size() == preparedMapping.size() && primitive.empty(), "invalid mapping preparation call");
check(shader != nullptr && context.size() <= preparedMapping.size() && primitive.empty(), "invalid mapping preparation call");
mappedPixel = shader;
std::copy(context.begin(), context.end(), preparedMapping.begin());
preparedCount = context.size();
++mappings;
}
@ -141,8 +207,9 @@ int main() {
try {
testIdentity();
testMapping();
testUpdateMapping();
testRejections();
check(mappings == 3u && links == 2u, "mapping preparation call count changed");
check(mappings == 7u && links == 5u, "mapping preparation call count changed");
LibcRunShutdown_nid_postfix();
std::puts("AGC interpolant mapping tests passed");
return 0;

View File

@ -116,8 +116,8 @@ void testIndirect() {
check(storage.words == expected, "count setter modified unrelated packet data");
}
const auto before = storage.words;
for (const auto count : {0x4000u, 0xffffffffu}) {
expectFailure([&] { sizes[i](count); });
for (const auto count : {0x4000u, 0xffffffffu, 0xf5f5039cu}) {
check(sizes[i](count) == 20, "indirect size depends on the count");
expectFailure([&] { setters[i](packet, count); });
}
expectFailure([&] { setters[i](nullptr, 0); });

View File

@ -0,0 +1,164 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <memory>
#include <new>
#include <stdexcept>
#include <vector>
extern "C" int APS5_VABI sceAgcSetAmmSemaphoreMemory(void* memory, std::uint64_t sizeInBytes);
extern "C" int APS5_VABI sceAgcGetSemaphoreLabel(std::uint32_t index, void** label);
namespace {
constexpr std::uint64_t blockBytes = 0x4000u;
constexpr std::uint64_t labelBytes = 32u;
constexpr std::uint64_t counterBytes = 8u;
constexpr std::uint64_t memoryBytes = 2u * blockBytes;
constexpr std::uint64_t storageBytes = 4u * blockBytes;
constexpr std::uint32_t labelCount = static_cast<std::uint32_t>(memoryBytes / labelBytes);
constexpr std::uint8_t guardByte = 0xa5u;
constexpr std::uint8_t counterByte = 0x5au;
struct AlignedRelease {
void operator()(std::uint8_t* memory) const { ::operator delete(memory, std::align_val_t{blockBytes}); }
};
std::unique_ptr<std::uint8_t, AlignedRelease> storage;
void check(bool condition, const char* message) {
if (!condition) throw std::runtime_error(message);
}
template <typename TAction>
void expectFailure(TAction action) {
try {
action();
} catch (const std::runtime_error& error) {
check(error.what()[0] != '\0', "empty exception message");
return;
}
throw std::runtime_error("expected an exception");
}
std::uint8_t* memory() {
return storage.get() + blockBytes;
}
std::vector<std::uint8_t> snapshot() {
return {storage.get(), storage.get() + storageBytes};
}
void checkUnchanged(const std::vector<std::uint8_t>& before, const char* message) {
check(std::equal(before.begin(), before.end(), storage.get()), message);
}
void fillStorage() {
std::fill(storage.get(), storage.get() + storageBytes, guardByte);
for (std::uint64_t label = 0; label < memoryBytes; label += labelBytes) {
std::fill(memory() + label, memory() + label + counterBytes, counterByte);
std::fill(memory() + label + counterBytes, memory() + label + labelBytes, std::uint8_t{0});
}
}
void testUnregistered() {
std::array<void*, 3> labels{storage.get(), storage.get(), storage.get()};
expectFailure([&] { sceAgcGetSemaphoreLabel(0, &labels[1]); });
expectFailure([] { sceAgcGetSemaphoreLabel(0, nullptr); });
check(labels[0] == storage.get() && labels[1] == storage.get() && labels[2] == storage.get(), "a rejected semaphore label changed the output");
}
void testRegistrationRejections() {
const auto before = snapshot();
expectFailure([] { sceAgcSetAmmSemaphoreMemory(nullptr, memoryBytes); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(nullptr, 0); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory(), 0); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory() + 1, memoryBytes); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory() + labelBytes, blockBytes); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory(), blockBytes - 1u); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory(), blockBytes + labelBytes); });
expectFailure([] {
const auto top = std::numeric_limits<std::uintptr_t>::max() & ~static_cast<std::uintptr_t>(blockBytes - 1u);
sceAgcSetAmmSemaphoreMemory(reinterpret_cast<void*>(top), memoryBytes);
});
checkUnchanged(before, "a rejected registration changed memory");
testUnregistered();
}
void testUnsettledClearing() {
for (const std::uint64_t offset : {5u * labelBytes + counterBytes, memoryBytes - 1u}) {
memory()[offset] = 0x77u;
const auto before = snapshot();
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory(), memoryBytes); });
checkUnchanged(before, "a registration with unsettled clearing changed memory");
testUnregistered();
memory()[offset] = 0;
}
}
void testRegistration() {
const auto before = snapshot();
check(sceAgcSetAmmSemaphoreMemory(memory(), memoryBytes) == 0, "registering the AMM semaphore memory failed");
check(std::all_of(memory(), memory() + memoryBytes, [](std::uint8_t byte) { return byte == 0; }), "registration did not clear the semaphore counters");
check(std::equal(before.begin(), before.begin() + blockBytes, storage.get()), "registration wrote before the semaphore memory");
check(std::equal(before.begin() + blockBytes + memoryBytes, before.end(), memory() + memoryBytes), "registration wrote past the semaphore memory");
}
void testLabels() {
for (const std::uint32_t index : {0u, 1u, 7u, labelCount / 2u, labelCount - 1u}) {
std::array<void*, 3> labels{storage.get(), nullptr, storage.get()};
check(sceAgcGetSemaphoreLabel(index, &labels[1]) == 0, "a semaphore label lookup failed");
check(labels[1] == memory() + index * labelBytes, "incorrect semaphore label address");
check(labels[0] == storage.get() && labels[2] == storage.get(), "a semaphore label lookup wrote past its output");
}
}
void testLabelRejections() {
for (const std::uint32_t index : {labelCount, labelCount + 1u, std::numeric_limits<std::uint32_t>::max()}) {
void* label = storage.get();
expectFailure([&] { sceAgcGetSemaphoreLabel(index, &label); });
check(label == storage.get(), "a rejected semaphore label changed the output");
}
expectFailure([] { sceAgcGetSemaphoreLabel(0, nullptr); });
}
void testRepeatedRegistration() {
std::fill(memory(), memory() + memoryBytes, std::uint8_t{0x3c});
const auto before = snapshot();
expectFailure([] { sceAgcSetAmmSemaphoreMemory(memory(), memoryBytes); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(storage.get(), blockBytes); });
expectFailure([] { sceAgcSetAmmSemaphoreMemory(nullptr, 0); });
checkUnchanged(before, "a repeated registration changed memory");
void* label = nullptr;
check(sceAgcGetSemaphoreLabel(labelCount - 1u, &label) == 0 && label == memory() + memoryBytes - labelBytes, "a repeated registration replaced the semaphore memory");
}
}
int main() {
try {
storage.reset(static_cast<std::uint8_t*>(::operator new(storageBytes, std::align_val_t{blockBytes})));
fillStorage();
testUnregistered();
testRegistrationRejections();
testUnsettledClearing();
testRegistration();
testLabels();
testLabelRejections();
testRepeatedRegistration();
storage.reset();
LibcRunShutdown_nid_postfix();
std::puts("AGC semaphore tests passed");
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
try { LibcRunShutdown_nid_postfix(); }
catch (const std::exception& shutdown) { std::fprintf(stderr, "shutdown: %s\n", shutdown.what()); }
return 1;
}
}

View File

@ -7,16 +7,20 @@
#include <array>
#include <span>
#include <stdexcept>
#include <string>
#include <iostream>
extern "C" int APS5_VABI sceAgcLinkShaders(ShaderRegister*, ShaderRegister*, const void*, const Shader*, const Shader*, std::uint32_t);
extern "C" int APS5_VABI sceAgcCreatePrimState(ShaderRegister*, ShaderRegister*, const Shader*, const Shader*, std::uint32_t);
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister*, const Shader*, const Shader*);
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_0100(ShaderRegister*, const Shader*, const Shader*);
namespace {
std::array<ShaderRegister, 2> preparedContext;
std::array<ShaderRegister, 3> preparedPrimitive;
std::size_t stageCount = 0;
std::array<const Shader*, 2> linkedStages{};
std::size_t linkedStageCount = 0;
std::size_t linkedContextCount = 0;
unsigned preparations = 0;
unsigned mappings = 0;
unsigned links = 0;
@ -26,13 +30,63 @@ const Shader* mappedPixel = nullptr;
void Require(bool condition) {
if (!condition) throw std::runtime_error("shader helper preparation mismatch");
}
void OptionalGeometryOutputRegister(ShaderSpecialRegs& special, const Shader& vertex, const Shader& hull) {
using namespace ShaderRegs;
special.vgt_gs_out_prim_type = {};
std::array<ShaderRegister, 2> noGeometryContext{};
Require(sceAgcCreatePrimState(noGeometryContext.data(), nullptr, nullptr, &vertex, 7) == 0);
Require(noGeometryContext[0].offset == VGT_SHADER_STAGES_EN && noGeometryContext[1].offset == VGT_GS_OUT_PRIM_TYPE && noGeometryContext[1].value == static_cast<std::uint32_t>(GsOutputPrimitiveType::Rectangle2D));
bool rejectedMissingHullOutput = false;
try { static_cast<void>(sceAgcCreatePrimState(noGeometryContext.data(), nullptr, &hull, &vertex, 7)); }
catch (const std::runtime_error&) { rejectedMissingHullOutput = true; }
Require(rejectedMissingHullOutput);
special.vgt_shader_stages_en.value = VGT_SHADER_STAGES_GS_BIT;
bool rejectedMissingGeometryOutput = false;
try { static_cast<void>(sceAgcCreatePrimState(noGeometryContext.data(), nullptr, nullptr, &vertex, 7)); }
catch (const std::runtime_error&) { rejectedMissingGeometryOutput = true; }
Require(rejectedMissingGeometryOutput);
special.vgt_shader_stages_en.value = 0;
special.vgt_gs_out_prim_type = {VGT_GS_OUT_PRIM_TYPE, 2};
}
void HandBuiltUserVgprRegister() {
using namespace ShaderRegs;
ShaderSpecialRegs handBuilt{};
handBuilt.ge_cntl = {GE_CNTL, 0x100u};
handBuilt.vgt_shader_stages_en = {VGT_SHADER_STAGES_EN, 0x2412010u};
handBuilt.vgt_gs_out_prim_type = {0x2ceu, 2};
handBuilt.ge_user_vgpr_en = {GE_USER_VGPR1, 0};
Shader preRaster{};
preRaster.type = static_cast<std::uint8_t>(ShaderBinaryType::Gs);
preRaster.specials = &handBuilt;
std::array<ShaderRegister, 2> context{};
std::array<ShaderRegister, 3> primitive{};
preparations = 0;
Require(sceAgcCreatePrimState(context.data(), primitive.data(), nullptr, &preRaster, 4) == 0);
Require(context[0].offset == VGT_SHADER_STAGES_EN && context[0].value == 0x2412010u && context[1].offset == VGT_GS_OUT_PRIM_TYPE && context[1].value == static_cast<std::uint32_t>(GsOutputPrimitiveType::Triangles));
Require(primitive[0].offset == GE_CNTL && primitive[0].value == 0x100u && primitive[1].offset == GE_USER_VGPR1 && primitive[1].value == 0 && primitive[2].offset == VGT_PRIMITIVE_TYPE && primitive[2].value == 4);
Require(preparations == 1 && stageCount == 1 && preparedPrimitive[1].offset == GE_USER_VGPR1 && preparedPrimitive[1].value == 0);
handBuilt.ge_cntl.offset = 0x25cu;
std::string message;
try { static_cast<void>(sceAgcCreatePrimState(context.data(), primitive.data(), nullptr, &preRaster, 4)); }
catch (const std::runtime_error& error) { message = error.what(); }
Require(message.find("GE_CNTL") != std::string::npos && message.find("0x25c") != std::string::npos);
}
}
extern "C" void AgcDriverResolveGraphicsStagesAbi_nid_postfix(std::span<const Shader* const> stages, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive) {
Require(context.size() == 2 && primitive.size() == 3);
std::copy(context.begin(), context.end(), preparedContext.begin());
std::copy(primitive.begin(), primitive.end(), preparedPrimitive.begin());
stageCount = stages.size();
Require((context.size() == 2 || context.size() == 34) && primitive.size() == 3);
if (context.size() == 2) {
std::copy(context.begin(), context.end(), preparedContext.begin());
std::copy(primitive.begin(), primitive.end(), preparedPrimitive.begin());
stageCount = stages.size();
} else {
Require(stages.size() == 2);
std::copy(stages.begin(), stages.end(), linkedStages.begin());
linkedStageCount = stages.size();
linkedContextCount = context.size();
}
++preparations;
}
@ -79,7 +133,7 @@ int main() {
context.back().value = primitive.back().value = 0xdeadbeef;
const auto prepare = [&] { Require(sceAgcCreatePrimState(outputs & 1 ? context.data() : nullptr, outputs & 2 ? primitive.data() : nullptr, hs, &vertex, 7) == 0); };
if (primitiveFirst) prepare();
Require(sceAgcCreateInterpolantMapping(interpolants.data(), &vertex, &pixel) == 0);
Require(sceAgcCreateInterpolantMapping_0100(interpolants.data(), &vertex, &pixel) == 0);
if (!primitiveFirst) prepare();
Require(preparations == 1 && mappings == 1 && links == 1 && stageCount == (hs ? 2u : 1u));
Require(preparedContext[0].offset == VGT_SHADER_STAGES_EN && preparedContext[1].offset == VGT_GS_OUT_PRIM_TYPE);
@ -91,6 +145,19 @@ int main() {
}
}
}
preparations = 0;
std::array<ShaderRegister, 2> patchContext{};
std::array<ShaderRegister, 3> patchPrimitive{};
Require(sceAgcCreatePrimState(patchContext.data(), patchPrimitive.data(), nullptr, &vertex, 9) == 0);
Require(preparations == 0 && patchContext[0].offset == VGT_SHADER_STAGES_EN && patchContext[0].value == 0 && patchPrimitive[2].offset == VGT_PRIMITIVE_TYPE && patchPrimitive[2].value == 9);
ShaderSpecialRegs hullSpecial = special;
hullSpecial.vgt_shader_stages_en.value = VGT_SHADER_STAGES_HS_BIT;
hull.specials = &hullSpecial;
Require(sceAgcCreatePrimState(patchContext.data(), patchPrimitive.data(), &hull, &vertex, 4) == 0);
Require(preparations == 0 && patchContext[0].value == VGT_SHADER_STAGES_HS_BIT && patchPrimitive[2].value == 4);
Require(sceAgcCreatePrimState(patchContext.data(), patchPrimitive.data(), &hull, &vertex, 9) == 0);
Require(preparations == 1 && stageCount == 2 && preparedContext[0].value == VGT_SHADER_STAGES_HS_BIT && preparedPrimitive[2].value == 9 && patchPrimitive[2].value == 9);
hull.specials = &special;
std::array<ShaderRegister, 34> linkedContext{};
std::array<ShaderRegister, 3> linkedPrimitive{};
for (auto& value : linkedContext) value.value = 0xdeadbeef;
@ -104,23 +171,29 @@ int main() {
for (const auto value : linkedContext) Require(value.value == 0xdeadbeef);
for (const auto value : linkedPrimitive) Require(value.value == 0xdeadbeef);
rejected = false;
try { sceAgcCreateInterpolantMapping(interpolants.data(), &vertex, &pixel); }
try { sceAgcCreateInterpolantMapping_0100(interpolants.data(), &vertex, &pixel); }
catch (const std::runtime_error&) { rejected = true; }
Require(rejected);
for (const auto value : interpolants) Require(value.value == 0xdeadbeef);
rejectLink = false;
pixel.num_input_semantics = 33;
rejected = false;
try { sceAgcCreateInterpolantMapping(interpolants.data(), &vertex, &pixel); }
try { sceAgcCreateInterpolantMapping_0100(interpolants.data(), &vertex, &pixel); }
catch (const std::runtime_error&) { rejected = true; }
Require(rejected);
for (const auto value : interpolants) Require(value.value == 0xdeadbeef);
pixel.num_input_semantics = 1;
preparations = mappings = links = 0;
linkedStageCount = linkedContextCount = 0;
Require(sceAgcLinkShaders(linkedContext.data(), linkedPrimitive.data(), nullptr, &vertex, &pixel, 7) == 0);
Require(preparations == 2 && linkedStageCount == 2 && linkedContextCount == linkedContext.size());
Require(linkedStages[0] == &vertex && linkedStages[1] == &pixel);
preparations = mappings = links = 0;
Require(sceAgcCreatePrimState(nullptr, nullptr, nullptr, nullptr, 7) == 0);
Require(sceAgcCreateInterpolantMapping(interpolants.data(), &vertex, nullptr) == 0);
Require(sceAgcCreateInterpolantMapping_0100(interpolants.data(), &vertex, nullptr) == 0);
Require(preparations == 0 && mappings == 0 && links == 0);
OptionalGeometryOutputRegister(special, vertex, hull);
HandBuiltUserVgprRegister();
std::cout << "shader helper preparation tests passed\n";
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_COMPUTEPIPELINECAPTURE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_COMPUTEPIPELINECAPTURE_HPP
#include <vulkan/vulkan.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <span>
#include <string>
#include <vector>
namespace AgcDriver {
struct ComputeDescriptorBinding {
std::uint32_t binding = 0;
VkDescriptorType type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
std::uint32_t count = 1;
VkShaderStageFlags stages = VK_SHADER_STAGE_COMPUTE_BIT;
VkDescriptorBindingFlags flags = 0;
};
struct ComputeDescriptorSetLayout {
VkDescriptorSetLayoutCreateFlags flags = 0;
std::vector<ComputeDescriptorBinding> bindings;
};
struct ComputeSpecialization {
std::uint32_t id = 0;
std::uint32_t value = 0;
};
struct ComputePipelineCapture {
static constexpr std::uint32_t Version = 1;
static constexpr std::uint32_t MaxSpirvWords = 8u * 1024u * 1024u;
static constexpr std::size_t MaxFileBytes = 36u * 1024u * 1024u;
std::vector<std::uint32_t> spirv;
std::vector<ComputeDescriptorSetLayout> sets;
std::vector<VkPushConstantRange> pushConstants;
std::vector<ComputeSpecialization> specialization;
std::uint32_t requiredSubgroupSize = 0;
VkPipelineCreateFlags flags = 0;
VkPipelineShaderStageCreateFlags stageFlags = 0;
std::string deviceName;
std::uint32_t vendorId = 0;
std::uint32_t deviceId = 0;
std::uint32_t driverVersion = 0;
std::uint32_t apiVersion = 0;
std::array<std::uint8_t, VK_UUID_SIZE> pipelineCacheUuid{};
void Validate() const;
std::vector<std::byte> Encode() const;
static ComputePipelineCapture Decode(std::span<const std::byte> bytes);
static ComputePipelineCapture Read(const std::filesystem::path& path);
std::filesystem::path Write(const std::filesystem::path& directory) const;
std::string Identity() const;
};
struct ComputePipelineReplayResult {
double moduleMilliseconds = 0;
double layoutMilliseconds = 0;
double pipelineMilliseconds = 0;
double cacheMilliseconds = 0;
double totalMilliseconds = 0;
std::string deviceName;
std::uint32_t vendorId = 0;
std::uint32_t deviceId = 0;
std::uint32_t driverVersion = 0;
std::uint32_t apiVersion = 0;
std::array<std::uint8_t, VK_UUID_SIZE> pipelineCacheUuid{};
std::size_t initialCacheBytes = 0;
std::vector<std::byte> cache;
};
}
#endif

View File

@ -25,6 +25,7 @@ struct DisplayBuffer {
};
std::size_t DisplayBufferSize(const DisplayBuffer& buffer);
std::size_t DisplayBufferOffset(const DisplayBuffer& buffer, std::uint32_t x, std::uint32_t y);
std::vector<std::byte> DecodeDisplayBuffer(const DisplayBuffer& buffer, std::span<const std::byte> source);
std::vector<std::byte> ReadDisplayBuffer(const DisplayBuffer& buffer);
std::array<std::byte, 4> DisplayBufferClearPixel(const DisplayBuffer& buffer, Graphics::DccKeys keys);

View File

@ -10,6 +10,8 @@ namespace AgcDriver {
VkFormat DisplayTexelFormat(std::uint64_t pixelFormat);
bool DisplayTenBit(std::uint64_t pixelFormat);
bool DisplayRedLow(std::uint64_t pixelFormat);
bool DisplayHalfFloat(std::uint64_t pixelFormat);
std::uint32_t DisplayTexelBytes(std::uint64_t pixelFormat);
enum class ResidentPresent : std::uint8_t { None, Blit, Convert };
ResidentPresent ResidentPresentPath(VkFormat storage, std::uint64_t pixelFormat, bool blitSource);

View File

@ -12,6 +12,7 @@ void Submit(const Packet* packet, std::uint32_t queue);
}
extern "C" void AgcDriverWaitIdle_nid_postfix();
extern "C" void AgcDriverRaiseWorkerThreadPriority_nid_postfix(const char* role);
extern "C" void AgcDriverLockVulkanLoader_nid_postfix();
extern "C" void AgcDriverUnlockVulkanLoader_nid_postfix();
extern "C" void AgcDriverShutdown_nid_postfix();

View File

@ -8,6 +8,8 @@ namespace AgcDriver::DriverDetail {
double TraceMs();
std::uint64_t SkippedShader();
void require(bool condition, const char* reason);
std::uint32_t readRegister(const Registers& registers, std::uint32_t offset);

View File

@ -82,6 +82,8 @@ struct DataMask {
enum class EntryOutcome { Equal, EqualData, Differing, Inaccessible, QueuedLabel, FlushingImage, PublishMoved, PendingMoved, ForgetMoved };
bool CacheableResult(const ShaderRecompiler::RecompileResult& compiled);
}
#endif

View File

@ -5,7 +5,7 @@
namespace AgcDriver::DriverDetail {
enum IndirectPath { IndirectGpu = 0, IndirectPendingImage = 1, IndirectCopiedWrite = 2, IndirectNotImported = 3, IndirectThreadDimensions = 4, IndirectFillKernel = 5, IndirectMisaligned = 6, IndirectDisabled = 7, IndirectPaths = 8 };
enum IndirectPath { IndirectGpu = 0, IndirectPendingImage = 1, IndirectCopiedWrite = 2, IndirectNotImported = 3, IndirectThreadDimensions = 4, IndirectFillKernel = 5, IndirectMisaligned = 6, IndirectDisabled = 7, IndirectWorkgroupMemory = 8, IndirectPaths = 9 };
}

View File

@ -37,6 +37,9 @@ void DecodeGraphicsPrograms(DrawDecode& decoded, const QueueState& queue, const
struct PreparedGraphicsStage {
std::shared_ptr<const ShaderSnapshot> snapshot;
PreparedShaders::Entry entry;
ShaderRecompiler::ShaderStage stage = ShaderRecompiler::ShaderStage::Vertex;
std::uint32_t pushOffset = 0;
std::shared_ptr<const ShaderRecompiler::RecompileResult> registration;
};
std::vector<PreparedGraphicsStage> PrepareGraphicsStages(const DrawDecode& decoded, const ShaderRecompiler::SpirvTarget& target);
@ -72,6 +75,19 @@ struct DrawEntryCounters {
std::chrono::steady_clock::time_point lastReport = std::chrono::steady_clock::now();
};
class DrawKeySightings {
public:
static constexpr std::size_t Ways = 4;
explicit DrawKeySightings(std::size_t keys);
bool SeenBefore(std::uint64_t key);
private:
std::vector<std::uint64_t> keys;
std::vector<std::uint8_t> filled;
std::vector<std::uint8_t> next;
std::size_t bucketMask = 0;
};
enum class DrawVerdict { Drawn, Nothing, Rejected };
struct StageCapture {
@ -81,6 +97,8 @@ struct StageCapture {
std::uint32_t pushOffset = 0;
};
bool DecodeProgramsCurrent(const DrawDecode& decode, const ShaderRegistry& registry);
}
#endif

View File

@ -0,0 +1,12 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_DRIVER_DRAW_DRAWREGISTERKEY_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_DRIVER_DRAW_DRAWREGISTERKEY_HPP
#include "prx/libSceAgcDriver/Execution/include/QueueState.hpp"
namespace AgcDriver::DriverDetail {
std::uint64_t RegisterStateKey(const QueueState& queue, bool allUserWords = false, bool incremental = true);
}
#endif

View File

@ -44,6 +44,7 @@ namespace AgcDriver::DriverDetail {
class Driver {
public:
static Driver& Get();
static std::uint64_t GpuMapImportThreads();
~Driver();
void Shutdown();
void WaitIdle();
@ -53,12 +54,17 @@ public:
void SuspendPoint();
void RegisterVideoOutput(std::uint32_t handle, const std::shared_ptr<IVideoOutput>& output);
void UnregisterVideoOutput(std::uint32_t handle, const std::shared_ptr<IVideoOutput>& output);
void AttachWindow(const PresentationWindow& window);
void Present(const PresentationWindow& window, const DisplayBuffer* buffer, bool opaque, void (*gpuReady)(void*), void* context);
void ReleaseWindow(void* window);
void RegisterShader(const Shader* shader);
void ResolveShaderAbi(const Shader* shader, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive);
void ResolveGraphicsStagesAbi(std::span<const Shader* const> stages, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive);
void ResolveGraphicsAbi(const Shader* vertex, const Shader* pixel, std::uint32_t primitiveType);
static void FoldDrawOffsets(const ShaderRecompiler::RecompileResult& result, const DrawProgram& program, Pm4::DrawParameters& parameters);
static std::optional<Graphics::IndirectDrawPath> ClassifyIndirectDraw(const ShaderRecompiler::RecompileResult& result, const Graphics::State& graphics, const DrawProgram& frontProgram, const std::shared_ptr<VulkanDevice>& localDevice, Pm4::DrawParameters& drawParameters, bool traceIndirect);
static std::string dumpRequest(std::uint64_t address, const ShaderRecompiler::RecompileRequest& request);
DrawEntryCounters DrawCacheCounters();
private:
friend class SampledReadScope;
@ -73,6 +79,10 @@ private:
static bool copySegment(Submission& submission, const std::uint32_t* guest, std::size_t words, std::size_t& budget);
static void readRegisterLists(Submission& submission);
void waitForFlipRoom(const Submission& submission);
void holdFlipBehindWorker(const Submission& submission);
bool awaitsTitle(std::uint64_t awaited) const;
void noteAwaitingTitle(std::uint32_t queue, std::uint64_t awaited);
void releaseFlipHold();
void reserveOutputs(Submission& submission);
void executeRewindTail(const Submission& stalled);
void enqueue(Submission submission);
@ -105,6 +115,8 @@ private:
static std::size_t drawCacheEntries();
void accountDrawVariant(const DispatchVariant& variant, bool added);
void insertDrawEntry(std::uint64_t key, std::vector<std::shared_ptr<DispatchVariant>>& fresh, std::shared_ptr<const DrawDecode> decode);
bool admitDrawKey(std::uint64_t key);
void eraseDrawEntry(std::uint64_t key, const std::shared_ptr<DrawEntry>& expected);
std::shared_ptr<const DrawRecipe> findDrawRecipe(std::uint64_t key, const std::vector<std::shared_ptr<DispatchVariant>>& stages);
void attachDrawRecipe(std::uint64_t key, const std::vector<std::shared_ptr<DispatchVariant>>& stages, std::shared_ptr<const DrawRecipe> recipe);
void reportDrawCache(DrawEntryCounters& counters);
@ -119,22 +131,20 @@ private:
static bool drawPrecheck();
std::optional<DrawVerdict> precheckDraw(const QueueState& queue, const Submission& submission, std::span<const std::uint32_t> packet, const Pm4::DrawParameters& drawParameters, std::string& rejected, bool& traceIndirect);
static std::uint32_t drawUserWord(const DrawProgram& program, std::int32_t sgpr);
std::optional<Graphics::IndirectDrawPath> classifyIndirectDraw(const ShaderRecompiler::RecompileResult& result, const Graphics::State& graphics, const DrawProgram& frontProgram, const std::shared_ptr<VulkanDevice>& localDevice, Pm4::DrawParameters& drawParameters, bool traceIndirect);
DrawVerdict draw(QueueState& queue, std::span<const std::uint32_t> packet, const Submission& submission, std::string& rejected);
void addDriverPhases(DispatchClass which, const std::array<double, DriverPhaseCount>& ms, bool hit, bool validated);
static PendingDispatchPhases& pendingDispatchPhases();
static std::chrono::steady_clock::time_point& packetStartedAt();
static PendingDrawPhases& pendingDrawPhases();
void addDrawPhases(const std::array<double, DrawDriverPhaseCount>& ms, bool drawn, std::uint64_t captures);
void noteLabelStore(std::uint64_t address, std::span<const std::byte> bytes, std::uint64_t stamp);
bool storedSince(std::span<const std::uint32_t> packet, std::uint64_t address, std::size_t bytes, std::uint64_t received);
void noteLabelStore(std::uint64_t address, std::span<const std::byte> bytes, std::uint64_t stamp, std::uint32_t queue);
bool storedSince(std::span<const std::uint32_t> packet, std::uint64_t address, std::size_t bytes, std::uint64_t received, std::uint32_t* writer = nullptr);
static void traceLabel(std::span<const std::uint32_t> packet, std::uint32_t queue);
static std::array<WriteRecord, 16384>& writeHistory();
static std::size_t& writeCursor();
static void dumpPackets(std::span<const std::uint32_t> commands, const std::uint32_t* guest = nullptr);
static void validate(const Submission& submission, const std::uint32_t* guest = nullptr);
static void reportSkip(const char* kind, const std::string& what);
static std::string dumpRequest(std::uint64_t address, const ShaderRecompiler::RecompileRequest& request);
static bool matchesFillKernel(std::span<const std::uint32_t> code, const std::vector<std::uint32_t>& userData, const ShaderRecompiler::ShaderComputeStageInfo& compute);
static bool fillClearEnabled();
static bool fillClearExactOnly();
@ -176,6 +186,7 @@ private:
template<typename TVisit>
static void forEachWrittenBuffer(const ShaderRecompiler::RecompileResult& compiled, TVisit&& visit);
void noteWrittenBuffers(std::uint64_t program, std::uint32_t queue, const ShaderRecompiler::RecompileResult& compiled);
static void appendWrittenRanges(const ShaderRecompiler::RecompileResult& compiled, std::vector<std::pair<std::uint64_t, std::uint64_t>>& ranges);
void noteForeignWriter(std::uint64_t begin, std::uint64_t end, std::uint32_t queue);
void noteDrawWriters(std::span<const Graphics::CompiledShader> stages, std::uint32_t queue);
std::optional<WrittenBuffer> newestWriterLocked(std::uint64_t begin, std::uint64_t end) const;
@ -194,7 +205,41 @@ private:
static bool pollReapAll();
static bool pollTryEach();
static bool traceLateLabels();
void waitMemory(std::span<const std::uint32_t> packet, std::uint32_t queue, const PacketHistory& context, std::uint64_t received, bool heldAtSubmit);
void waitMemory(std::span<const std::uint32_t> packet, std::uint32_t queue, const PacketHistory& context, std::uint64_t received, bool heldAtSubmit, bool requireMemory = false);
struct PendingWait {
std::array<std::uint32_t, 8> words;
std::size_t count;
std::uint64_t received;
};
static std::vector<PendingWait>& pendingWaits();
static void notePendingWait(std::span<const std::uint32_t> packet, std::uint32_t queue, std::uint64_t received);
void landPendingWaits(std::uint32_t queue);
struct ResolvedDispatch {
std::uint64_t address = 0, key = 0, indirectArguments = 0;
std::array<std::uint32_t, 5> packet{};
std::shared_ptr<const ShaderSnapshot> registeredShader;
std::shared_ptr<const ShaderRecompiler::RecompileResult> compiledResult;
std::shared_ptr<DispatchVariant> keepVariant, attachVariant;
std::shared_ptr<ShaderMemory> shaderMemory;
std::vector<ShaderRecompiler::MemoryRegion> captured;
std::vector<std::uint32_t> liveWords;
std::shared_ptr<const ShaderRecompiler::ResourceCapture> capture;
bool dataHit = false, cached = false, validated = false;
std::chrono::steady_clock::time_point resolvedAt{};
};
struct GroupCaptureStats {
std::uint64_t runs = 0, resolved = 0, resolvedHits = 0, adopted = 0, addressMismatches = 0, keyMismatches = 0, failures = 0, stale = 0, labelOverlaps = 0, writtenBefore = 0, deviceRejects = 0;
double resolveMs = 0, resolveMaxMs = 0, ageMs = 0, ageMaxMs = 0;
std::chrono::steady_clock::time_point reported = std::chrono::steady_clock::now();
};
static std::map<std::size_t, ResolvedDispatch>& resolvedAhead();
static GroupCaptureStats& groupCaptureStats();
static std::size_t& currentPacketOffset();
static bool& resolvingAhead();
static bool& gateOpened();
void resolveGroupAhead(const Submission& submission, const QueueState& live, std::size_t from);
static void clearResolvedAhead();
static void reportGroupCapture(std::uint32_t queue);
static PollStats& pollStats();
static WaitOutcomes& waitOutcomes();
static Graphics::Recorder::LateStatistics& lateCountsSeen();
@ -266,6 +311,7 @@ private:
std::list<std::uint64_t> drawOrder;
std::mutex drawCacheMutex;
std::uint64_t drawCacheHits = 0, drawCacheEvictions = 0, drawCacheVariants = 0, drawCacheVariantBytes = 0;
std::optional<DrawKeySightings> drawKeySightings;
DrawEntryCounters drawEntryCounters;
@ -300,7 +346,11 @@ private:
std::uint64_t queue0Executing = 0;
std::atomic<std::uint32_t> orderHolders{0};
std::atomic<std::uint32_t> runningWorkers{0};
std::atomic<std::uint64_t> idleEpoch{0};
std::atomic<std::uint64_t> queue0Awaited{0};
std::atomic<std::uint32_t> flipsAhead{0};
std::atomic<std::uint32_t> flipHolders{0};
std::atomic<bool> queue0AwaitsTitle{false};
std::atomic<std::uint64_t> evidenceReads{0};
std::atomic<std::uint64_t> evidenceValidations{0};

View File

@ -0,0 +1,54 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_BUFFERFILL_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_BUFFERFILL_HPP
#include "Recompiler.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <span>
namespace AgcDriver::DriverDetail {
inline constexpr std::array<std::uint32_t, 18> PatternFillKernel{
0xbfa00001u, 0xd7460000u, 0x04010c0cu, 0xf4201a84u, 0xfa000000u, 0xbf8cc07fu,
0x7da8006au, 0xbf880009u, 0xf4201a84u, 0xfa000004u, 0xbf8cc07fu, 0x3602006au,
0xe0002000u, 0x80000101u, 0xbf8c3f70u, 0xe0102000u, 0x80010100u, 0xbf810000u
};
inline bool MatchesPatternFillKernel(std::span<const std::uint32_t> code, std::span<const std::uint32_t> userData, const ShaderRecompiler::ShaderComputeStageInfo& compute) {
if (userData.size() != 12 || compute.numThreads != std::array<std::uint32_t, 3>{64, 1, 1} || !compute.groupIdEnable[0] || compute.threadIdComponentCount != 1) return false;
if (code.size() < PatternFillKernel.size() || !std::equal(PatternFillKernel.begin(), PatternFillKernel.end(), code.begin())) return false;
for (const auto first : {0u, 4u, 8u}) {
if ((userData[first + 1] & 0xffff0000u) != (first == 8 ? 0x00100000u : 0x00040000u)) return false;
if (userData[first + 3] != (first == 8 ? 0x0004dfacu : 0x00014004u)) return false;
}
return userData[2] >= 1 && userData[10] >= 1;
}
struct PatternFillRange {
std::uint64_t source, destination, control, invocations;
std::uint32_t records;
[[nodiscard]] std::optional<std::size_t> UniformBytes(std::uint32_t count, std::uint32_t mask) const {
if (mask != 0) return std::nullopt;
const auto bytes = std::min({invocations, std::uint64_t{count}, std::uint64_t{records}}) * 4u;
if (destination % 16 != 0 || bytes % 16 != 0) return std::nullopt;
if (bytes != 0 && ((source < destination + bytes && destination < source + 4) || (control < destination + bytes && destination < control + 8))) return std::nullopt;
return static_cast<std::size_t>(bytes);
}
};
inline std::optional<PatternFillRange> DecodePatternFillRange(std::span<const std::uint32_t> userData, std::span<const std::uint32_t> packet) {
if (userData.size() != 12 || packet.size() < 5 || packet[2] != 1 || packet[3] != 1) return std::nullopt;
const std::uint64_t invocations = (packet[4] & 0x20u) != 0 ? packet[1] : std::uint64_t{packet[1]} * 64u;
if (invocations > (std::uint64_t{1} << 32u)) return std::nullopt;
const auto base = [&](std::size_t word) { return userData[word] | (static_cast<std::uint64_t>(userData[word + 1] & 0xffffu) << 32u); };
if (base(0) % 4 != 0 || base(8) % 4 != 0) return std::nullopt;
return PatternFillRange{base(0), base(4), base(8), invocations, userData[6]};
}
}
#endif

View File

@ -0,0 +1,30 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_MEMORY_DWORDPATTERNFILL_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_MEMORY_DWORDPATTERNFILL_HPP
#include "Recompiler.hpp"
#include "prx/libSceAgcDriver/Graphics/include/DccMetadata.hpp"
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <span>
#include <vector>
namespace AgcDriver::DriverDetail {
struct DwordPatternFill {
std::uint64_t base = 0;
std::size_t bytes = 0;
std::array<std::uint32_t, 4> pattern{};
};
std::optional<DwordPatternFill> MatchDwordPatternFill(std::span<const std::uint32_t> packet, std::span<const std::uint32_t> code, const std::vector<std::uint32_t>& userData, const ShaderRecompiler::ShaderComputeStageInfo& compute);
std::optional<DwordPatternFill> MatchZeroDwordFill(std::span<const std::uint32_t> packet, std::span<const std::uint32_t> code, const std::vector<std::uint32_t>& userData, const ShaderRecompiler::ShaderComputeStageInfo& compute);
std::optional<Graphics::MemoryValueFill> MatchMemoryValueBufferFill(std::span<const std::uint32_t> packet, std::span<const std::uint32_t> code, const std::vector<std::uint32_t>& userData, const ShaderRecompiler::ShaderComputeStageInfo& compute);
bool IsByteFill(const std::array<std::uint32_t, 4>& pattern);
std::optional<Graphics::DccKeys> KeysFillMemo(const std::array<std::uint32_t, 4>& pattern, bool coversStorageKeys, bool memoryValueFill);
}
#endif

View File

@ -29,6 +29,7 @@ struct Submission {
std::map<std::size_t, std::vector<std::uint32_t>> registerLists;
bool suspend = false;
bool waitFree = false;
bool holdsFlip = false;
std::uint64_t received = 0;
std::vector<std::uint64_t> labelWrites;

View File

@ -5,19 +5,34 @@
#include "prx/libSceAgcDriver/Execution/include/QueueState.hpp"
#include <array>
#include <optional>
#include <span>
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <functional>
#include <initializer_list>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
struct Shader;
namespace ShaderRecompiler {
class ShaderPreparationContext;
}
namespace AgcDriver {
class VulkanDevice;
}
namespace AgcDriver::DriverDetail {
struct ShaderSnapshot;
using ShaderRegistry = std::map<std::uint64_t, std::shared_ptr<const ShaderSnapshot>>;
using ShaderRegistry = std::map<std::uint64_t, std::vector<std::shared_ptr<const ShaderSnapshot>>>;
struct PreparedShaderState {
struct Entry {
@ -46,9 +61,14 @@ struct PreparedShaderState {
std::vector<RectangleProgress> rectangleProgress;
std::vector<std::weak_ptr<const ShaderSnapshot>> fragments;
bool rectangleRequested = false;
bool deferred = false;
};
struct PreparedShaders : PreparedShaderState {
std::mutex mutex;
std::condition_variable settled;
std::exception_ptr failure;
std::atomic<bool> demanded{false};
bool pending = false;
};
struct RegisteredShaderState {
@ -65,18 +85,38 @@ struct ShaderSnapshot {
std::vector<std::byte> header;
std::shared_ptr<PreparedShaders> prepared = std::make_shared<PreparedShaders>();
std::shared_ptr<const RegisteredShaderState> registeredState;
std::shared_ptr<std::atomic<std::uint8_t>> workgroupUse = std::make_shared<std::atomic<std::uint8_t>>(0u);
std::shared_ptr<std::atomic<std::uint8_t>> positionVectorUse = std::make_shared<std::atomic<std::uint8_t>>(0u);
};
std::shared_ptr<const ShaderSnapshot> ReadRawComputeShader(std::uint64_t address);
std::shared_ptr<const ShaderSnapshot> ReadRawShader(std::uint64_t address);
std::shared_ptr<const ShaderSnapshot> ProgramSnapshot(const ShaderRegistry& shaders, std::uint64_t address, std::initializer_list<std::uint8_t> types);
void NoteRawGraphicsDraw();
bool RawGraphicsDrawn();
bool ProgramUsesWorkgroup(const ShaderSnapshot& snapshot, std::size_t codeOffset);
// The PA_CL_VS_OUT_CNTL position export bits a vertex program is compiled with: none for a program
// without pos1..pos3 exports, so its artifact does not depend on them.
std::uint32_t PositionExportLayout(const ShaderSnapshot* snapshot, std::size_t codeOffset, std::span<const std::uint32_t> code, std::uint32_t paClVsOutCntl);
bool VertexWorkgroupRequired(const QueueState& queue, const ShaderRegistry& registry);
std::shared_ptr<const ShaderRecompiler::SourceHandle> PrepareShaderWithDiagnostics(const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::ShaderPreparationContext* preparation = nullptr);
std::uint64_t NullPixelProgramAddress();
ShaderSnapshot PrepareNullPixelProgram(const VulkanDevice& device);
std::optional<ShaderRecompiler::ShaderFloatMode> RegisteredFloatMode(const ShaderSnapshot& snapshot);
std::shared_ptr<const ShaderSnapshot> RegisteredHeader(const ShaderRegistry& registry, const Shader* shader);
std::shared_ptr<const ShaderSnapshot> RegisteredProgram(const ShaderRegistry& registry, std::uint64_t address, std::initializer_list<std::uint8_t> types);
void PublishRegisteredShader(std::shared_ptr<ShaderRegistry>& registry, const std::shared_ptr<const ShaderSnapshot>& snapshot);
void SubmitRegistrationPreparation(std::function<void()> task, const PreparedShaders* prepared = nullptr);
void PrioritizeRegistrationPreparation(PreparedShaders& prepared);
void SubmitLibraryPrebuild(std::function<void()> task);
void CloseRegistrationPreparation();
void ResolvePreparedGraphics(const ShaderSnapshot& front, const std::shared_ptr<const ShaderSnapshot>& fragment, std::uint32_t primitiveType, const ShaderRecompiler::SpirvTarget& target);
ShaderRecompiler::RectListShaders PreparedRectangle(const ShaderSnapshot& snapshot, std::uint64_t vertexId, std::uint64_t fragmentId);
ShaderRecompiler::RectListShaders DrawRectangle(const ShaderSnapshot& front, const std::shared_ptr<const ShaderSnapshot>& fragment, std::uint64_t vertexId, std::uint64_t fragmentId, const ShaderRecompiler::SpirvTarget& target);
std::shared_ptr<const ShaderRecompiler::SourceHandle> SourceHandleFor(const ShaderSnapshot& snapshot, std::size_t codeOffset, const ShaderRecompiler::RecompileRequest& request);
ShaderRecompiler::PreparedShaderInvocation InvocationFor(const ShaderSnapshot& snapshot, std::size_t codeOffset, const ShaderRecompiler::RecompileRequest& request);

View File

@ -12,7 +12,7 @@ struct SubmissionCosts {
std::atomic<std::uint64_t> submissions{0}, validateNs{0}, copyNs{0}, dequeueNs{0}, completeNs{0}, suspendNs{0}, suspends{0}, suspendsSkipped{0}, endSubmits{0}, endSkipped{0}, notifiesSkipped{0};
};
extern std::atomic<std::uint64_t> gpuLabels, completionLabels, notImportedLabels, noOpLabels, unlockedDrains;
extern std::atomic<std::uint64_t> gpuLabels, completionLabels, noOpLabels, unlockedDrains;
extern std::atomic<std::uint64_t> labelFallbacks[5];
@ -30,7 +30,7 @@ enum TrySite { TryLabel = 0, TryFlush, TryReap, TryPoll, TryIdle, TryCapture, Tr
extern std::atomic<std::uint64_t> triesFailed[TrySites];
extern std::atomic<std::uint64_t> storesOnGpu, storesBehindCompletions, storesOnCpu, storesDrained;
extern std::atomic<std::uint64_t> storesOnGpu, storesBehindCompletions, storesOnCpu, storesDrained, copiesToHostMemory;
extern std::map<std::uint32_t, std::uint64_t> drainCounts;

View File

@ -18,6 +18,7 @@ inline constexpr std::chrono::microseconds PollTryInterval{1000};
struct LabelStore {
std::uint64_t stamp = 0;
std::uint32_t value = 0;
std::uint32_t queue = 0xffffffffu;
};
struct WriteRecord {

View File

@ -0,0 +1,14 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_FRAGMENTBARYCENTRIC_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_FRAGMENTBARYCENTRIC_HPP
#include <vulkan/vulkan.h>
namespace AgcDriver {
inline bool FragmentShaderBarycentricUsable(VkDriverId driver, bool reported) {
return reported && driver != VK_DRIVER_ID_MOLTENVK;
}
}
#endif

View File

@ -30,6 +30,7 @@ void Read(std::uint64_t address, std::span<std::byte> destination, std::size_t a
// Variants for resources in heaps the guest commits on demand (partially resident textures, GPU
// scratch heaps): uncommitted pages read as zeros, are not compared, and are never stored.
void ReadCommitted(std::uint64_t address, std::span<std::byte> destination);
void ReadCommittedUnsynced(std::uint64_t address, std::span<std::byte> destination);
bool EqualsCommitted(std::uint64_t address, std::span<const std::byte> bytes);
// EqualsCommitted without the flush hook: the caller has decided that the recorded GPU work
// writing the range need not be waited for (the dispatch-cache validation in Driver.cpp).
@ -59,7 +60,7 @@ void WriteChanged(std::uint64_t address, std::span<const std::byte> current, std
// UnchangedSince is always false, so callers fall back to comparing bytes.
bool WriteWatched();
void Unwatch(std::uint64_t address, std::size_t bytes);
bool ImportWatched(std::uint64_t address, std::size_t bytes, const std::function<bool()>& import);
bool ImportWatched(std::uint64_t address, std::size_t bytes, const std::function<bool()>& import, bool staysWatched = true);
bool Watched(std::uint64_t address, std::size_t bytes);
std::uint64_t CollectWrites(std::uint64_t address, std::size_t bytes);
bool UnchangedSince(std::uint64_t address, std::size_t bytes, std::uint64_t generation);
@ -71,10 +72,13 @@ struct UnchangedQuery {
};
bool WrittenSince(std::uint64_t address, std::size_t bytes, std::uint64_t generation);
bool UnchangedSinceAll(std::span<const UnchangedQuery> queries);
std::uint64_t CollectCommittedWrites(std::uint64_t address, std::size_t bytes, std::vector<std::pair<std::uint64_t, std::uint64_t>>& ranges);
bool UnchangedCommittedSince(std::span<const std::pair<std::uint64_t, std::uint64_t>> ranges, std::uint64_t generation);
// Returns the generation the blocks were stamped with (0 when the arena is not write-watched):
// UnchangedSince(range, it) holds until the next store over the range.
std::uint64_t MarkWritten(std::uint64_t address, std::size_t bytes);
std::uint64_t StoreOwnBytes(std::uint64_t address, std::size_t bytes, const std::function<void()>& store);
std::uint64_t StoreOwnBytes(std::uint64_t address, std::span<const std::byte> source);
bool StoredOver(std::uint64_t address, std::size_t bytes, std::uint64_t generation);
// Collect epoch: within one epoch a range already collected is not walked again, CollectWrites
// returns the current generation instead. A guest write landing between two collects of the same
@ -100,6 +104,7 @@ std::uint64_t CollectWritesUncached(std::uint64_t address, std::size_t bytes);
// tracker mutex, so every collect that bumped before it has finished its walk and every later
// collect stamps newer.
std::uint64_t TrackerGeneration();
std::uint64_t NewestStamp(std::uint64_t address, std::size_t bytes);
// Whether no CPU write touched the range since `generation`: an uncached resetting collect of the
// range's pages first (a game store not collected yet becomes a block stamp), then the compare over
// the stamps collects make (dirty pages), not the MarkWritten stamps of the driver's own GPU label
@ -113,7 +118,6 @@ bool UnchangedSinceCollected(std::uint64_t address, std::size_t bytes, std::uint
// watched arena, or for a generation of 0, a block reads as changed.
constexpr std::uint8_t BlockUnchanged = 0;
constexpr std::uint8_t BlockWritten = 1;
constexpr std::uint8_t BlockMaybeWritten = 2;
bool ChangedBlocks(std::uint64_t address, std::size_t bytes, std::span<const std::uint64_t> generations, std::span<std::uint8_t> changed, std::span<std::uint8_t> cpu = {});
// Serializes device work: draws, dispatches, presentation and the deferred write-backs below. The
@ -148,6 +152,7 @@ GpuMutexType& GpuMutex();
// work the hold deferred to run without it (the recorder's release of the objects completed batches
// kept). One hook, set once; it must not take GpuMutex itself.
void SetGpuUnlockHook(void (*hook)());
std::uint64_t GpuHoldSerial();
// Debug aid (APS5_ASSERT_GPU_LOCK=1): aborts with a [lock] line naming `where` when the calling
// thread does not hold GpuMutex. Recording, submits, command batches and the detiler's pools must
// only be reached under it (a resource build's stage A runs without it, see ShaderResources).
@ -182,6 +187,7 @@ unsigned long long CodeOffset(const void* address);
// every read and store through this interface calls first. Code that reads guest memory directly
// calls FlushGpuWrites itself.
void SetFlushHook(void (*hook)(std::uint64_t address, std::size_t bytes));
void SetReadGuard(void (*guard)(std::uint64_t address, std::size_t bytes));
void FlushGpuWrites(std::uint64_t address, std::size_t bytes);
// Moves with every ForgetPages call (the libc invalidator: memory unmapped or re-registered): odd
// while the call stores its page states, moved past it after, so a reader that loads an even

View File

@ -1,6 +1,8 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PERFORMANCETIMER_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PERFORMANCETIMER_HPP
#include "prx/libSceAgcDriver/Execution/include/PerformanceTrace.hpp"
#include "prx/libSceAgcDriver/Execution/include/TracyZone.hpp"
#include <algorithm>
#include <chrono>
#include <cstddef>
@ -258,11 +260,11 @@ private:
class PerformanceTimer {
public:
explicit PerformanceTimer(const char* scope) : frame(PerformanceContext::Current()), scope(scope) {
explicit PerformanceTimer(const char* scope) : frame(PerformanceContext::Current()), trace(PerformanceTrace::Recording() ? PerformanceTrace::Thread() : nullptr), scope(scope) {
if (frame != nullptr) {
total = frame->Get(scope, "total");
}
if (frame != nullptr) start = Clock::now();
if (frame != nullptr || trace != nullptr) start = Clock::now();
previous = start;
}
@ -274,8 +276,12 @@ public:
}
void Finish() {
if (frame == nullptr) return;
zone.End();
if (frame == nullptr && trace == nullptr) return;
const auto end = Clock::now();
if (trace != nullptr) trace->Add(scope, nullptr, start, end);
trace = nullptr;
if (frame == nullptr) return;
if (tail != nullptr) frame->Add(tail, end - previous);
frame->Add(total, end - start);
frame = nullptr;
@ -287,10 +293,13 @@ public:
}
void Mark(const char* stage, std::uint64_t bytes = 0) {
if (frame == nullptr) return;
if (frame == nullptr && trace == nullptr) return;
const auto now = Clock::now();
if (tail == nullptr) tail = frame->Get(scope, "tail");
frame->Add(frame->Get(scope, stage), now - previous, bytes);
if (trace != nullptr) trace->Add(scope, stage, previous, now);
if (frame != nullptr) {
if (tail == nullptr) tail = frame->Get(scope, "tail");
frame->Add(frame->Get(scope, stage), now - previous, bytes);
}
previous = now;
}
@ -298,7 +307,9 @@ private:
using Clock = FrameTiming::Clock;
FrameTiming* frame;
TraceThread* trace;
const char* scope;
[[no_unique_address]] TracyZone zone{scope};
FrameTiming::Metric* total = nullptr;
FrameTiming::Metric* tail = nullptr;
Clock::time_point start{};

View File

@ -0,0 +1,437 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PERFORMANCETRACE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PERFORMANCETRACE_HPP
#include <algorithm>
#include <array>
#include <atomic>
#include <charconv>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace AgcDriver {
class VulkanDevice;
class TraceWindow {
public:
using Clock = std::chrono::steady_clock;
enum class Edge { None, Open, Close };
static std::optional<TraceWindow> Parse(const char* frames, const char* seconds) {
if (frames == nullptr && seconds == nullptr) return std::nullopt;
if (frames != nullptr && seconds != nullptr) throw std::invalid_argument("APS5_TRACE_FRAMES and APS5_TRACE_SECONDS cannot be set together");
const std::string_view name = frames != nullptr ? "APS5_TRACE_FRAMES" : "APS5_TRACE_SECONDS";
const std::string_view text = frames != nullptr ? frames : seconds;
const auto colon = text.find(':');
std::uint64_t start = 0;
std::uint64_t length = 0;
if (colon == std::string_view::npos || !number(text.substr(0, colon), start) || !number(text.substr(colon + 1), length) || length == 0)
throw std::invalid_argument(std::string(name) + "=" + std::string(text) + " is not <start>:<length> with a length above 0");
return TraceWindow(frames != nullptr, start, length);
}
Edge Present(std::uint64_t present, Clock::duration elapsed) {
if (state == State::Closed) return Edge::None;
if (state == State::Waiting) {
if (frames ? present < start : wholeSeconds(elapsed) < start) return Edge::None;
state = State::Open;
openedPresent = present;
openedAt = elapsed;
return Edge::Open;
}
if (frames ? present - openedPresent < length : wholeSeconds(elapsed - openedAt) < length) return Edge::None;
state = State::Closed;
return Edge::Close;
}
std::string Describe() const {
return std::string(frames ? "frames " : "seconds ") + std::to_string(start) + ":" + std::to_string(length);
}
private:
enum class State { Waiting, Open, Closed };
TraceWindow(bool frames, std::uint64_t start, std::uint64_t length) : frames(frames), start(start), length(length) {}
static bool number(std::string_view text, std::uint64_t& value) {
const auto end = text.data() + text.size();
const auto [last, error] = std::from_chars(text.data(), end, value);
return !text.empty() && error == std::errc{} && last == end;
}
static std::uint64_t wholeSeconds(Clock::duration elapsed) {
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::seconds>(elapsed).count());
}
bool frames;
std::uint64_t start;
std::uint64_t length;
State state = State::Waiting;
std::uint64_t openedPresent = 0;
Clock::duration openedAt{};
};
class TraceThread {
public:
using Clock = std::chrono::steady_clock;
static constexpr std::size_t DefaultCapacity = 262144;
static constexpr Clock::duration MinimumSlice = std::chrono::microseconds(20);
struct Slice {
const char* scope;
const char* stage;
Clock::time_point begin;
Clock::duration length;
};
struct Total {
const char* scope;
const char* stage;
Clock::duration length;
std::uint64_t count;
};
struct Snapshot {
std::string name;
std::span<const Slice> slices;
std::vector<Total> totals;
bool dropped = false;
};
TraceThread(std::string name, const std::atomic<std::uint64_t>& presents, std::size_t capacity = DefaultCapacity)
: name(std::move(name)), presents(presents), slices(std::make_unique<Slice[]>(capacity)), capacity(capacity) {}
TraceThread(const TraceThread&) = delete;
TraceThread& operator=(const TraceThread&) = delete;
void Add(const char* scope, const char* stage, Clock::time_point begin, Clock::time_point end) {
const auto length = end - begin;
account(scope, stage, length);
const auto present = presents.load(std::memory_order_relaxed);
if (!sampled || present != sampledPresent) {
if (sampled) append({nullptr, nullptr, sampleBegin, folded});
sampled = true;
sampledPresent = present;
sampleBegin = begin;
folded = {};
}
if (length < MinimumSlice) folded += length;
else append({scope, stage, begin, length});
}
Snapshot Collect() const {
Snapshot snapshot{name, {slices.get(), used.load(std::memory_order_acquire)}, {}, false};
for (const auto& entry : entries) {
const auto* scope = entry.scope.load(std::memory_order_acquire);
if (scope == nullptr) continue;
snapshot.totals.push_back({scope, entry.stage.load(std::memory_order_relaxed), Clock::duration(entry.length.load(std::memory_order_relaxed)), entry.count.load(std::memory_order_relaxed)});
}
snapshot.dropped = dropped.load(std::memory_order_relaxed);
return snapshot;
}
private:
struct Entry {
std::atomic<const char*> scope{nullptr};
std::atomic<const char*> stage{nullptr};
std::atomic<Clock::rep> length{0};
std::atomic<std::uint64_t> count{0};
};
void append(const Slice& slice) {
const auto index = used.load(std::memory_order_relaxed);
if (index == capacity) {
dropped.store(true, std::memory_order_relaxed);
return;
}
slices[index] = slice;
used.store(index + 1, std::memory_order_release);
}
void account(const char* scope, const char* stage, Clock::duration length) {
const auto key = reinterpret_cast<std::uintptr_t>(scope) ^ (reinterpret_cast<std::uintptr_t>(stage) >> 3);
const auto hash = static_cast<std::size_t>((static_cast<std::uint64_t>(key) * 0x9e3779b97f4a7c15ull) >> 55);
for (std::size_t probe = 0; probe < entries.size(); ++probe) {
auto& entry = entries[(hash + probe) % entries.size()];
const auto* current = entry.scope.load(std::memory_order_relaxed);
if (current == nullptr) {
entry.stage.store(stage, std::memory_order_relaxed);
entry.scope.store(scope, std::memory_order_release);
} else if (current != scope || entry.stage.load(std::memory_order_relaxed) != stage) {
continue;
}
entry.length.store(entry.length.load(std::memory_order_relaxed) + length.count(), std::memory_order_relaxed);
entry.count.store(entry.count.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
return;
}
dropped.store(true, std::memory_order_relaxed);
}
const std::string name;
const std::atomic<std::uint64_t>& presents;
const std::unique_ptr<Slice[]> slices;
const std::size_t capacity;
std::atomic<std::size_t> used{0};
std::atomic<bool> dropped{false};
std::array<Entry, 512> entries;
bool sampled = false;
std::uint64_t sampledPresent = 0;
Clock::time_point sampleBegin{};
Clock::duration folded{};
};
struct TraceSummary {
std::string commit;
std::optional<bool> dirty;
std::vector<std::pair<std::string, std::string>> environment;
std::string gpu;
std::string driver;
std::string os;
std::uint32_t width = 0;
std::uint32_t height = 0;
std::string window;
std::uint64_t firstPresent = 0;
double gpuBusyMs = 0;
std::string trace;
};
struct TraceGpuRange {
const char* name;
double beginNs;
double endNs;
};
struct TraceClockSample {
double gpuNs = 0;
std::chrono::steady_clock::time_point cpu{};
};
class TraceFormat {
public:
using Clock = std::chrono::steady_clock;
static constexpr std::array<std::string_view, 5> WorkerBusyScopes{"Driver.Packet", "Driver.Suspend", "Driver.EndSubmission", "Driver.Rewind", "Driver.Completion"};
static constexpr std::string_view WorkerWaitScope = "Driver.WorkerWait";
static constexpr std::string_view WorkerPrefix = "queue worker ";
static constexpr std::size_t TopPhases = 8;
static void AppendString(std::string& output, std::string_view text) {
output += '"';
for (const char character : text) {
const auto byte = static_cast<unsigned char>(character);
if (character == '"' || character == '\\') {
output += '\\';
output += character;
} else if (byte < 0x20 || byte >= 0x7f) {
char escaped[8];
std::snprintf(escaped, sizeof escaped, "\\u%04x", static_cast<unsigned>(byte));
output += escaped;
} else {
output += character;
}
}
output += '"';
}
static std::string Name(const char* scope, const char* stage) {
return stage == nullptr ? std::string(scope) : std::string(scope) + "." + stage;
}
static std::string Events(std::uint64_t process, Clock::time_point origin, std::span<const TraceThread::Snapshot> threads, std::size_t presenter, std::span<const Clock::time_point> presents, std::uint64_t firstPresent) {
std::string output = "{\"traceEvents\":[\n";
bool first = true;
const auto event = [&](std::string_view name, const char* phase, Clock::time_point at, std::size_t tid) {
if (!first) output += ",\n";
first = false;
output += "{\"name\":";
AppendString(output, name);
char text[96];
std::snprintf(text, sizeof text, ",\"ph\":\"%s\",\"ts\":%.3f,\"pid\":%llu,\"tid\":%llu", phase, microseconds(at - origin), static_cast<unsigned long long>(process), static_cast<unsigned long long>(tid));
output += text;
};
event("process_name", "M", origin, 0);
output += ",\"args\":{\"name\":\"AnyPS5\"}}";
for (std::size_t index = 0; index < threads.size(); ++index) {
const auto& thread = threads[index];
const auto tid = index + 1;
event("thread_name", "M", origin, tid);
output += ",\"args\":{\"name\":";
AppendString(output, thread.name);
output += "}}";
std::vector<TraceThread::Slice> slices(thread.slices.begin(), thread.slices.end());
std::stable_sort(slices.begin(), slices.end(), [](const auto& a, const auto& b) { return a.begin != b.begin ? a.begin < b.begin : a.length > b.length; });
const auto folded = thread.name + " folded";
for (const auto& slice : slices) {
char text[64];
if (slice.scope == nullptr) {
event(folded, "C", slice.begin, tid);
std::snprintf(text, sizeof text, ",\"args\":{\"ms\":%.3f}}", milliseconds(slice.length));
} else {
event(Name(slice.scope, slice.stage), "X", slice.begin, tid);
std::snprintf(text, sizeof text, ",\"dur\":%.3f}", microseconds(slice.length));
}
output += text;
}
}
for (std::size_t index = 0; index + 1 < presents.size(); ++index) {
event("present", "i", presents[index], presenter + 1);
output += ",\"s\":\"g\",\"args\":{\"present\":" + std::to_string(firstPresent + index) + "}}";
}
output += "\n]}\n";
return output;
}
static std::vector<TraceThread::Slice> GpuSlices(std::span<const TraceGpuRange> ranges, const TraceClockSample& first, const TraceClockSample& last, Clock::time_point origin) {
const double gpuSpan = last.gpuNs - first.gpuNs;
const double scale = gpuSpan > 0 ? std::chrono::duration<double, std::nano>(last.cpu - first.cpu).count() / gpuSpan : 1.0;
const auto map = [&](double gpuNs) { return first.cpu + std::chrono::duration_cast<Clock::duration>(std::chrono::duration<double, std::nano>((gpuNs - first.gpuNs) * scale)); };
std::vector<TraceThread::Slice> slices;
for (const auto& range : ranges) {
const auto begin = map(range.beginNs);
const auto end = map(range.endNs);
if (end <= begin || begin < origin) continue;
slices.push_back({range.name, nullptr, begin, end - begin});
}
return slices;
}
static std::string Summary(const TraceSummary& summary, std::span<const TraceThread::Snapshot> threads, std::span<const Clock::time_point> presents) {
const auto count = presents.empty() ? std::size_t{0} : presents.size() - 1;
const auto span = presents.empty() ? Clock::duration{} : presents.back() - presents.front();
std::vector<double> frames;
for (std::size_t index = 1; index < presents.size(); ++index) frames.push_back(milliseconds(presents[index] - presents[index - 1]));
std::sort(frames.begin(), frames.end());
const auto percentile = [&](double fraction) { return frames.empty() ? 0.0 : frames[std::min(frames.size() - 1, static_cast<std::size_t>(fraction * static_cast<double>(frames.size())))]; };
const double perPresent = count != 0 ? 1.0 / static_cast<double>(count) : 0.0;
std::string output = "{\"commit\":";
AppendString(output, summary.commit);
output += ",\"dirty\":";
output += summary.dirty.has_value() ? (*summary.dirty ? "true" : "false") : "null";
output += ",\"env\":{";
for (std::size_t index = 0; index < summary.environment.size(); ++index) {
if (index != 0) output += ',';
AppendString(output, summary.environment[index].first);
output += ':';
AppendString(output, summary.environment[index].second);
}
output += "},\"gpu\":";
AppendString(output, summary.gpu);
output += ",\"driver\":";
AppendString(output, summary.driver);
output += ",\"os\":";
AppendString(output, summary.os);
output += ",\"resolution\":";
AppendString(output, std::to_string(summary.width) + "x" + std::to_string(summary.height));
output += ",\"window\":{\"spec\":";
AppendString(output, summary.window);
output += ",\"first_present\":" + std::to_string(summary.firstPresent);
output += ",\"ms\":" + number(milliseconds(span)) + "}";
output += ",\"presents\":" + std::to_string(count);
output += ",\"frame_ms\":{\"p50\":" + number(percentile(0.5)) + ",\"p90\":" + number(percentile(0.9)) + ",\"p99\":" + number(percentile(0.99)) + ",\"max\":" + number(frames.empty() ? 0.0 : frames.back()) + "}";
output += ",\"gpu_busy_ms_per_present\":" + number(summary.gpuBusyMs * perPresent);
output += ",\"worker_busy_pct\":{";
bool firstWorker = true;
std::map<std::string, Clock::duration> phases;
bool dropped = false;
for (const auto& thread : threads) {
dropped = dropped || thread.dropped;
Clock::duration busy{};
for (const auto& total : thread.totals) {
const std::string_view scope = total.scope;
if (total.stage == nullptr && std::find(WorkerBusyScopes.begin(), WorkerBusyScopes.end(), scope) != WorkerBusyScopes.end()) busy += total.length;
if (scope != WorkerWaitScope) phases[Name(total.scope, total.stage)] += total.length;
}
if (!thread.name.starts_with(WorkerPrefix)) continue;
if (!firstWorker) output += ',';
firstWorker = false;
AppendString(output, thread.name);
output += ':' + number(span != Clock::duration{} ? 100.0 * static_cast<double>(busy.count()) / static_cast<double>(span.count()) : 0.0);
}
output += "},\"top_phases_ms_per_frame\":{";
std::vector<std::pair<std::string, Clock::duration>> top(phases.begin(), phases.end());
std::stable_sort(top.begin(), top.end(), [](const auto& a, const auto& b) { return a.second > b.second; });
for (std::size_t index = 0; index < top.size() && index < TopPhases; ++index) {
if (index != 0) output += ',';
AppendString(output, top[index].first);
output += ':' + number(milliseconds(top[index].second) * perPresent);
}
output += "},\"trace_dropped\":";
output += dropped ? "true" : "false";
output += ",\"trace\":";
AppendString(output, summary.trace);
output += "}\n";
return output;
}
private:
static double microseconds(Clock::duration elapsed) {
return std::chrono::duration<double, std::micro>(elapsed).count();
}
static double milliseconds(Clock::duration elapsed) {
return std::chrono::duration<double, std::milli>(elapsed).count();
}
static std::string number(double value) {
char text[32];
std::snprintf(text, sizeof text, "%.3f", value);
return text;
}
};
class PerformanceTrace {
public:
static bool Configured() {
static const bool configured = std::getenv("APS5_TRACE_FRAMES") != nullptr || std::getenv("APS5_TRACE_SECONDS") != nullptr;
return configured;
}
static void BindThread(const char* name, std::size_t capacity = TraceThread::DefaultCapacity);
static void Present(std::uint32_t width, std::uint32_t height, const VulkanDevice* device);
static void GpuRange(const char* name, double beginNs, double endNs) {
if (!Recording()) return;
std::lock_guard lock(gpuMutex);
if (gpuRanges.size() == gpuRanges.capacity()) {
gpuDropped = true;
return;
}
gpuRanges.push_back({name, beginNs, endNs});
}
static bool Recording() {
return recording.load(std::memory_order_relaxed);
}
static TraceThread* Thread() {
return local;
}
static void StopOutput();
private:
inline static std::atomic<bool> recording{false};
inline static std::atomic<std::uint64_t> presentCount{0};
inline static thread_local TraceThread* local = nullptr;
inline static std::mutex gpuMutex;
inline static std::vector<TraceGpuRange> gpuRanges;
inline static bool gpuDropped = false;
};
}
#endif

View File

@ -0,0 +1,14 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PIPELINELINKOPTIMIZATION_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PIPELINELINKOPTIMIZATION_HPP
#include <vulkan/vulkan.h>
namespace AgcDriver {
inline bool PipelineLinkTimeOptimizationUsable(VkDriverId driver) {
return driver != VK_DRIVER_ID_NVIDIA_PROPRIETARY;
}
}
#endif

View File

@ -81,7 +81,7 @@ inline bool DrawOpcode(std::uint32_t opcode) { return opcode == 0x27 || opcode =
std::string Name(std::uint32_t header);
// A PM4 type-2 packet is a one-dword filler (command-buffer padding); type 3 and type 0 carry a
// dword count in bits 29:16. Type 1 is undefined.
inline bool FillerPacket(std::uint32_t header) { return (header >> 30u) == 2u; }
inline bool FillerPacket(std::uint32_t header) { return (header >> 30u) == 2u || header == 0xffff1000u; }
inline std::size_t PacketWords(std::uint32_t header) { return FillerPacket(header) ? 1u : static_cast<std::size_t>((header >> 16u) & 0x3fffu) + 2u; }
std::string_view UnsupportedReason(std::uint32_t header);
void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue);
@ -140,12 +140,15 @@ struct MemoryCopy {
std::size_t bytes;
};
std::optional<MemoryCopy> DecodeMemoryCopy(std::span<const std::uint32_t> packet);
std::uint32_t DmaSource(std::span<const std::uint32_t> packet);
std::uint32_t DmaDestination(std::span<const std::uint32_t> packet);
// A DISPATCH_INDIRECT's arguments: the guest address of its three group-count dwords (no memory
// access, so the GPU can read them in place: VulkanDevice::DispatchIndirect), the DISPATCH_DIRECT
// packet made by reading them there (through the checked guest memory path, which waits for
// recorded GPU work that writes them), and both steps in one for the packet.
std::uint64_t DispatchArgumentAddress(std::span<const std::uint32_t> packet, const QueueState& queue);
std::array<std::uint32_t, 5> ReadDispatchArguments(std::uint64_t arguments, std::uint32_t initiator);
std::array<std::uint32_t, 3> PartialGroupThreads(const std::array<std::uint32_t, 3>& groups, const std::array<std::uint32_t, 3>& numThreads);
std::array<std::uint32_t, 5> ResolveDispatch(std::span<const std::uint32_t> packet, const QueueState& queue);
DrawParameters ResolveDraw(std::span<const std::uint32_t> packet, const QueueState& queue);

View File

@ -0,0 +1,27 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PRESENTMODE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_PRESENTMODE_HPP
#include <vulkan/vulkan.h>
#include <algorithm>
#include <span>
#include <stdexcept>
#include <string_view>
namespace AgcDriver {
inline VkPresentModeKHR SelectPresentMode(const char* requested, std::span<const VkPresentModeKHR> supported) {
VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
if (requested != nullptr) {
const std::string_view name(requested);
if (name == "mailbox") mode = VK_PRESENT_MODE_MAILBOX_KHR;
else if (name == "immediate") mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
else if (name == "fifo_latest_ready") mode = VK_PRESENT_MODE_FIFO_LATEST_READY_KHR;
else if (name != "fifo") throw std::runtime_error("Vulkan presentation: ANYPS5_PRESENT_MODE must be fifo, fifo_latest_ready, mailbox or immediate");
}
if (std::find(supported.begin(), supported.end(), mode) == supported.end()) throw std::runtime_error("Vulkan presentation: the surface does not support the requested present mode");
return mode;
}
}
#endif

View File

@ -25,6 +25,7 @@ struct PresentationWindow {
}
extern "C" void AgcDriverAttachWindow_nid_postfix(const AgcDriver::PresentationWindow& window);
extern "C" void AgcDriverPresentClear_nid_postfix(const AgcDriver::PresentationWindow& window, bool opaque, void (*gpuReady)(void*), void* context);
extern "C" void AgcDriverPresentBuffer_nid_postfix(const AgcDriver::PresentationWindow& window, const AgcDriver::DisplayBuffer& buffer, void (*gpuReady)(void*), void* context);
extern "C" void AgcDriverReleaseWindow_nid_postfix(void* window);

View File

@ -1,6 +1,7 @@
#pragma once
#include <array>
#include <atomic>
#include <condition_variable>
#include <cstdio>
#include <deque>
@ -56,6 +57,8 @@ public:
return true;
}
void Print(const char* text) { Print("%s", text); }
template<typename... TArgs>
void Print(const char* format, TArgs... args) {
std::array<char, 2048> local{};
@ -135,14 +138,21 @@ private:
std::thread worker;
};
inline std::atomic<ProfileOutput*> createdProfileOutput{nullptr};
inline ProfileOutput& ProfileOutput_nid_no_patch() {
static ProfileOutput output([](std::string_view text) {
if (std::fwrite(text.data(), 1, text.size(), stderr) != text.size() || std::fflush(stderr) != 0)
throw std::runtime_error("profile output write failed");
});
createdProfileOutput.store(&output, std::memory_order_release);
return output;
}
inline void StopProfileOutput_nid_no_patch() {
if (auto* output = createdProfileOutput.load(std::memory_order_acquire)) output->Stop();
}
template<typename... TArgs>
void ProfilePrint_nid_no_patch(const char* format, TArgs... args) {
ProfileOutput_nid_no_patch().Print(format, args...);

View File

@ -9,8 +9,10 @@
#include <stdexcept>
#include <utility>
#include <map>
#include <memory>
#include <array>
#include <optional>
#include <span>
#include <string>
#include <vector>
@ -22,6 +24,29 @@ public:
using mapped_type = std::uint32_t;
using value_type = std::pair<const std::uint32_t, std::uint32_t>;
class Mask {
public:
explicit Mask(std::vector<std::uint64_t> bits) : bits(std::move(bits)) {}
bool Contains(std::uint32_t offset) const { return offset / 64 < bits.size() && ((bits[offset / 64] >> (offset % 64)) & 1u) != 0; }
private:
std::vector<std::uint64_t> bits;
};
class Reference {
public:
Reference(Registers& owner, std::uint32_t offset) : owner(owner), offset(offset) {}
operator std::uint32_t() const { return owner.values[offset]; }
Reference& operator=(std::uint32_t value) { owner.insert_or_assign(offset, value); return *this; }
Reference& operator=(const Reference& other) { return *this = static_cast<std::uint32_t>(other); }
Reference& operator|=(std::uint32_t value) { return *this = static_cast<std::uint32_t>(*this) | value; }
Reference& operator&=(std::uint32_t value) { return *this = static_cast<std::uint32_t>(*this) & value; }
Reference& operator^=(std::uint32_t value) { return *this = static_cast<std::uint32_t>(*this) ^ value; }
Reference& operator+=(std::uint32_t value) { return *this = static_cast<std::uint32_t>(*this) + value; }
private:
Registers& owner;
std::uint32_t offset;
};
class const_iterator {
public:
using iterator_category = std::forward_iterator_tag;
@ -56,6 +81,18 @@ public:
using iterator = const_iterator;
Registers() = default;
Registers(const Registers&) = default;
Registers& operator=(const Registers&) = default;
Registers(Registers&& other) noexcept : values(std::move(other.values)), present(std::move(other.present)), entries(std::exchange(other.entries, 0)), mask(std::move(other.mask)), fingerprint(std::exchange(other.fingerprint, 0)) {}
Registers& operator=(Registers&& other) noexcept {
if (this == &other) return *this;
values = std::move(other.values);
present = std::move(other.present);
entries = std::exchange(other.entries, 0);
mask = std::move(other.mask);
fingerprint = std::exchange(other.fingerprint, 0);
return *this;
}
Registers(std::initializer_list<std::pair<std::uint32_t, std::uint32_t>> entries) {
for (const auto& [offset, value] : entries) emplace(offset, value);
}
@ -67,33 +104,48 @@ public:
const_iterator upper_bound(std::uint32_t offset) const { return {this, nextPresent(static_cast<std::size_t>(offset) + 1)}; }
bool contains(std::uint32_t offset) const { return offset < values.size() && ((present[offset / 64] >> (offset % 64)) & 1u) != 0; }
std::size_t count(std::uint32_t offset) const { return contains(offset) ? 1 : 0; }
template <class TVisit>
void ForEach(TVisit&& visit) const {
for (std::size_t word = 0; word < present.size(); ++word) {
for (auto bits = present[word]; bits != 0; bits &= bits - 1) {
const auto offset = word * 64 + static_cast<std::size_t>(std::countr_zero(bits));
visit(static_cast<std::uint32_t>(offset), values[offset]);
}
}
}
std::size_t size() const { return entries; }
bool empty() const { return entries == 0; }
void clear() {
values.clear();
present.clear();
entries = 0;
fingerprint = 0;
}
std::pair<const_iterator, bool> emplace(std::uint32_t offset, std::uint32_t value) {
if (contains(offset)) return {const_iterator{this, offset}, false};
mark(offset) = value;
changeFingerprint(offset, value);
return {const_iterator{this, offset}, true};
}
std::pair<const_iterator, bool> insert_or_assign(std::uint32_t offset, std::uint32_t value) {
if (contains(offset)) {
if (values[offset] == value) return {const_iterator{this, offset}, false};
changeFingerprint(offset, values[offset]);
values[offset] = value;
changeFingerprint(offset, value);
return {const_iterator{this, offset}, false};
}
mark(offset) = value;
changeFingerprint(offset, value);
return {const_iterator{this, offset}, true};
}
std::uint32_t& operator[](std::uint32_t offset) {
if (contains(offset)) return values[offset];
return mark(offset) = 0;
Reference operator[](std::uint32_t offset) {
if (!contains(offset)) emplace(offset, 0);
return {*this, offset};
}
std::uint32_t& at(std::uint32_t offset) {
Reference at(std::uint32_t offset) {
if (!contains(offset)) throw std::out_of_range("register is not set");
return values[offset];
return {*this, offset};
}
const std::uint32_t& at(std::uint32_t offset) const {
if (!contains(offset)) throw std::out_of_range("register is not set");
@ -101,6 +153,7 @@ public:
}
std::size_t erase(std::uint32_t offset) {
if (!contains(offset)) return 0;
changeFingerprint(offset, values[offset]);
present[offset / 64] &= ~(std::uint64_t{1} << (offset % 64));
--entries;
return 1;
@ -113,8 +166,31 @@ public:
}
return a == end() && b == other.end();
}
std::uint64_t Fingerprint(const std::shared_ptr<const Mask>& selected) const {
if (mask != selected) {
fingerprint = RecomputeFingerprint(*selected);
mask = selected;
}
return fingerprint;
}
std::uint64_t RecomputeFingerprint(const Mask& selected) const {
std::uint64_t result = 0;
for (const auto [offset, value] : *this) {
if (selected.Contains(offset)) result ^= contribution(offset, value);
}
return result;
}
private:
static std::uint64_t contribution(std::uint32_t offset, std::uint32_t value) {
auto hash = ((static_cast<std::uint64_t>(offset) << 32u) | value) + 0x9e3779b97f4a7c15ull;
hash = (hash ^ (hash >> 30u)) * 0xbf58476d1ce4e5b9ull;
hash = (hash ^ (hash >> 27u)) * 0x94d049bb133111ebull;
return hash ^ (hash >> 31u);
}
void changeFingerprint(std::uint32_t offset, std::uint32_t value) {
if (mask != nullptr && mask->Contains(offset)) fingerprint ^= contribution(offset, value);
}
static constexpr std::size_t End = ~std::size_t{0};
std::uint32_t& mark(std::uint32_t offset) {
if (offset >= values.size()) {
@ -137,9 +213,11 @@ private:
std::vector<std::uint32_t> values;
std::vector<std::uint64_t> present;
std::size_t entries = 0;
mutable std::shared_ptr<const Mask> mask;
mutable std::uint64_t fingerprint = 0;
};
inline Registers InitialContextRegisters() {
inline Registers BuildInitialContextRegisters() {
Registers result{
{0x200, 0}, {0x201, 0}, {0x202, 0xcc0010}, {0x203, 0},
{0x204, 0}, {0x205, 0}, {0x206, 1087}, {0x207, 0},
@ -156,11 +234,13 @@ inline Registers InitialContextRegisters() {
{0x318, 0}, {0x31b, 0}, {0x31c, 0}, {0x31d, 0},
{0x390, 0}, {0x3b0, 0}, {0x3b8, 0}
};
for (std::uint32_t i = 0; i < 32; ++i) result.emplace(0x191 + i, 0);
for (std::uint32_t i = 0; i < 8; ++i) {
result.emplace(0x1e0 + i, 0x20010001);
result.emplace(0x31c + 0xfu * i, 0);
}
for (std::uint32_t i = 0; i < 16; ++i) {
result.emplace(0x2fe + i, 0);
result.emplace(0x94 + 2 * i, 0x80000000);
result.emplace(0x95 + 2 * i, 0x40004000);
result.emplace(0xb4 + 2 * i, 0);
@ -170,6 +250,11 @@ inline Registers InitialContextRegisters() {
return result;
}
inline Registers InitialContextRegisters() {
static const Registers& initial = *new Registers(BuildInitialContextRegisters());
return initial;
}
struct Predication {
std::uint64_t address = 0;
std::uint32_t operation = 0;
@ -177,11 +262,12 @@ struct Predication {
};
struct QueueState {
static constexpr std::size_t ConstantRamWords = 0x3000;
Registers shader;
Registers context = InitialContextRegisters();
Registers userConfig{{0x24a, 0}, {0x24b, 0}};
std::optional<Registers> savedContext;
std::array<std::uint32_t, 0x3000> constantRam{};
std::vector<std::uint32_t> constantRam;
std::uint64_t indexBase = 0;
std::uint64_t drawIndirectBase = 0;
std::uint64_t dispatchIndirectBase = 0;
@ -194,6 +280,17 @@ struct QueueState {
void ClearContext() {
context = InitialContextRegisters();
}
std::span<const std::uint32_t> ConstantRam() const {
static const std::array<std::uint32_t, ConstantRamWords> unwritten{};
if (constantRam.empty()) return unwritten;
return constantRam;
}
std::span<std::uint32_t> WritableConstantRam() {
if (constantRam.empty()) constantRam.resize(ConstantRamWords);
return constantRam;
}
};
}

Some files were not shown because too many files have changed in this diff Show More