Commit Graph
6138 Commits
Author SHA1 Message Date
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
AymanFEandClaude Opus 5.5 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 <[email protected]>
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à FranchandClaude 0c20cab656 perf(agc): render with dynamic rendering when pipelines come from libraries
Co-Authored-By: Claude <[email protected]>
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à FranchandClaude 0a04c8658c perf(agc): link graphics pipelines from per-stage libraries
Co-Authored-By: Claude <[email protected]>
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à FranchandClaude 43cc101910 docs(technical-debt): record the lossy Windows file identity fold
Co-Authored-By: Claude <[email protected]>
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
raghav314andClaude Opus 5.5 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 <[email protected]>
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 SchusterandClaude Opus 5.5 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 <[email protected]>
2026-10-10 10:57:02 +02:00
Scott SchusterandClaude Opus 5.5 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 <[email protected]>
2026-10-10 10:57:02 +02:00
Scott SchusterandClaude Opus 5.5 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 <[email protected]>
2026-10-10 10:57:02 +02:00