Commit Graph
5229 Commits
Author SHA1 Message Date
Yunus Shaikh d21b0801a4 Merge upstream main into perf/shader-image-table-reuse-v3
Brings the series onto main 4e9a2a871 (#1193, #1201, #1202, #6060,
#6333 and the descriptor word tracking of 682b07eb0).

Resolutions:
- ShaderMemory: the column memo's supplied and spilled blocks now sit
  on #1193's page vector, page pool and word masks. Pages are found by
  binary search, since a spilled block can add many pages, and a block
  placed into a lazily read page fills the rest of the 16-word blocks it
  touches, so a later lazy read never overwrites placed words.
- ResourceMaterializer and SharedValues: the selected-record path and
  the words index carry availableDwordMask, as the snapshot hash does.
  A selected record's dwords past the end of its buffer count as read
  zeros, which is what a scalar buffer load returns there, so a key past
  the heap still selects a null image without reading the heap.
- DescriptorCache: kept table sets live beside #1201's recycled sets.
- Tests and CMake: both sides' tests are kept.
2026-10-15 08:54:44 -07:00
Yunus Shaikh 25cfce3bda perf(agc): compare two captures' shared table words by identity in the draw cache
The draw cache sets each fresh stage capture against the variants it keeps (insertDrawEntry), and
the dispatch cache sets a fresh capture against its front variant, by comparing every captured word.
A 32,768-record table column is 262,144 of them, so each compare went through 1 MiB on each side
even when both captures had copied the column from the same shared block.

A variant now records the words it copied from a block the shader memory shares (SharedWords: where
they sit in the capture and in the block, and a weak reference to the block; consecutive pages of
one block join into one entry). SameCapturedWords takes the words both captures copied from the
same place of the same block as equal, since a block never changes, and compares the words around
them as before. Two blocks with equal words, words read into pages and a released block fall back
to the word compare. The reference is weak, so a kept variant holds no block alive, and a released
block's identity cannot pass to a new one: its control block stays until the last weak reference
goes.
2026-10-15 08:54:33 -07:00
Yunus Shaikh 077bc20a24 perf(shader): reuse an unchanged image table's resolution by reference on a result memo miss
A result memo miss resolves every image table of the snapshot again: ResolveImageTables decodes each
distinct T#, builds the element and poison indices and fills one map record per key, which is most
of a miss for a large table. A miss whose table did not change is common: another buffer, flat SRT
word or user data word changes the result key while the column is the one the column memo shares.

ResolveImageTablesShared keeps the last resolutions and hands one out by reference when the variant
(its id), the reducing state of the direct samplers paired with table images and every column match:
base, size, records, keys, fault, outside, and the column's codes and distinct T#s by identity. The
memo holds those shared values, so a block it compares cannot be freed and reused for other words;
a column read again is a new block and resolves again even when its words are equal.

It keeps at most 4 resolutions per variant and 256 in all within 8 Mi words, counting the columns
their keys keep alive, least recently used first out, under one mutex. A resolution is immutable
once made and is shared between threads read-only. APS5_NO_TABLE_RESOLUTION_REUSE=1 turns it off.
ImageTableReuseCounts gains the resolutions made and the ones shared.
2026-10-15 08:54:33 -07:00
Yunus Shaikh 992222d309 perf(agc): keep an unwritten table column's words by reference in the shader memory
When the write tracker vouched for an unwritten image table column, the capture still copied each of
its words into ShaderMemory's pages (supplyWords) so they would be in the captured regions, and
Regions() then found them again bit by bit. On a 32,768-record column that is a 1 MiB copy per
capture (about 120 us here) and a scan of 262,144 read bits per Regions() call (about 230 us), and
the draw path calls TakeRecentRegions() and Regions() once each per stage.

The memo now keeps a column's words in one immutable block (SrtGuestWords), and supplyWords hands
that block over. ShaderMemory keeps a reference and reports its runs page by page, the regions a
read of the same words reports, merged in address order with the pages and the initial regions; a
second stage that supplies the same block only marks it recent again. The words reach pages only
when they must: a later read in the same ShaderMemory that touches them first moves the whole block
into its pages (spilled), so a word is never reported twice, and a block that overlaps pages already
fetched or another block's runs is copied as before. A spilled block stays referenced until the
ShaderMemory goes, so the regions already taken from it stay valid. ShaderMemory::Supplies() counts
the words shared, copied and spilled.
2026-10-15 08:54:32 -07:00
Yunus Shaikh d816062960 perf(shader): share an unchanged image table column with every snapshot that reuses it
A capture that reused a memoized image table column still copied it: each record's state and code
and the distinct T#s went from the memo into the snapshot, the snapshot rebuilt its codes from the
states, and the column's per-record vectors were allocated before the memo was even looked up. Every
Recompile then hashed the codes and the distinct T#s word by word for the result memo. On a
32,768-record column of distinct T#s that was about 155 us of copying per capture and 410 us of
hashing per Recompile here, for a column nothing wrote.

A column is now built once into immutable shared values (SharedValues: its codes, its distinct T#s
and its read ranges) and the memo keeps that column. A capture that reuses it takes a reference, so
two captures of an unchanged table share one column and copy nothing, and the per-record vectors
are allocated only when the column is walked. The codes index the column's own distinct T#s
(ImageTableColumnSnapshot::words) instead of a list shared by the shader's columns, so every column
of a shader is shared whole, not only the first. A column read again after a write is a new one:
the snapshots holding the old one keep it unchanged. The result memo hashes each shared value once
and keeps the hash in it; equal contents hash equal whether they are shared or not.

ImageTableReuseCounts gains the reuses that shared a column and the columns built.
2026-10-15 08:54:31 -07:00
Adrià 02a1b772ed Merge pull request #5770 from simonbronk/fix/kernel-mprotect-undefined-bits
fix(libkernel): drop undefined protection bits in sceKernelMprotect
2026-10-15 17:53:02 +02:00
Leonardo 17f08ae814 Merge branch 'main' into feat/voiceqos-endpoints 2026-10-15 17:52:30 +02:00
Yunus Shaikh f697e1a41b docs(libkernel): move the host stack protect entry next to the other protect entries
The entry now sits with the other sceKernelMprotect entries for
DirectMemory.cpp, before the Windows guest module image protection one,
instead of after the setcontext entry, where #5918 adds its own.
2026-10-15 08:52:22 -07:00
Claude 76cc70c245 fix(agc): overestimate single-sample draws with centroid inputs
A draw with PA_SC_CONSERVATIVE_RASTERIZATION_CNTL 0x6001 and
SPI_PS_INPUT_ENA.PERSP_CENTROID or LINEAR_CENTROID threw in DecodeState,
whatever its rasterized sample count. With PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES
0 the single rasterized sample is the pixel centre, which is where the
recompiler already puts the centroid barycentrics, so such a draw now
decodes to overestimation. More rasterized samples, and a single-sample
draw raised to a multisampled color target, still throw.

Extends agc_driver_graphics and records the inference in the driver's
technical debt.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01XJ3RTcWpqBBdVE8QRtKxJD
2026-10-15 15:47:02 +00:00
CapibaraandClaude Sonnet 5 66b0a6082e docs(libSceRegMgr): match house style for the unknown-function debt entry
The entry described the NID as sourced from the community firmware dump
alongside the signature, but nid_patcher derives the NID from the export
name itself; only the signature is unverified. Rewrite the entry to match
the house style used by libSceHttp2.md and libSceContentDelete.md: NID
inline, the importing title named, and a pinned link to the one external
source instead of an unlinked claim.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Vb2m1o8ZDHARkX6FTP9xuJ
2026-10-15 12:43:59 -03:00
SandstromPLandClaude Opus 5.5 716d811861 feat(libSceDiscMap): report no disc bitmap from the two disc map queries
Until Dawn (CUSA02636) bundles a libSceFios2.prx that imports two
libSceDiscMap functions, sceDiscMapIsRequestOnHDD (lbQKqsERhtE) and
ioKMruft1ek, and no host library exported them.

Both now return SCE_DISC_MAP_ERROR_NO_BITMAP_INFO (0x81100004) and
write nothing, as shadPS4 and fpPS4 do. That is the error the console
library returns while it has no disc bitmap loaded.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 20:54:46 +05:30
Yossi Yadgar a7ef31e103 docs(debt): note how closed standard descriptors are reopened 2026-10-15 18:19:21 +03:00
Yossi Yadgar 6473318a6b docs(debt): note which descriptors each LoadExec path passes on Linux 2026-10-15 18:17:21 +03:00
Yossi Yadgar 0d9af44626 docs(debt): note which descriptors LoadExec passes on Linux 2026-10-15 18:13:12 +03:00
fma-rc 451f11eafe fix(libkernel): report a 256 GiB AMM range starting on a 64 GiB boundary 2026-10-15 17:12:57 +02:00
Yunus Shaikh 5796ddfcfd fix(libkernel): commit a protect at the bottom of a host stack's reserve
HotSpot makes its stack guard zones with an RW protect of the lowest
pages of the thread's stack, then PROT_NONE, as it commits them on
native Windows (os::pd_create_stack_guard_pages, then os::guard_memory).
Below a host stack's guard page such a protect was only recorded, so the
pages stayed reserved: they could not be written after the RW protect,
and the zones never held.

A protect of reserved pages that starts at the bottom of the reserve and
stops short of the guard page now commits and protects them. The guard
page and the reserve above the range stay as they are, so the stack still
grows through the guard down to it, and the stack limit in the TEB still
follows the committed stack.

Windows moves the guard down by committing the pages below it as
read/write guard pages, committed or not. The zones therefore hold until
the stack is within one guard region of them (three pages on GitHub's
runners), and the pages the guard reaches then come in read/write. The
test checks both, and the debt entry says so.
2026-10-15 08:10:42 -07:00
Yunus Shaikh 3724c577d8 fix(libkernel): keep a host stack's guard page and reserve when protecting it on Windows
Committing the reserved pages of a host thread's stack before protecting
it, as the stack branch did for a range the arena doesn't own, also
cleared the guard page's PAGE_GUARD. The thread was left with no guard
and no reserve: an overflow ran into whatever lay below the stack instead
of raising a stack overflow, and the stack limit in the thread's TEB,
which Windows moves only when the guard page is hit, stopped following
the stack. A range that began inside the reserve also left the reserved
pages below it with no guard above them, so the stack could no longer
grow into them.

The stack branch now leaves the guard page and the reserved pages below
it as they are, and commits and protects only what lies above them;
reserved pages above the guard are still committed first. The protection
is recorded for the whole range, and a range of only reserved and guard
pages changes nothing on the host. The test protects the main thread's
whole stack and a reserved thread's whole stack and upper part, then
checks that the guard page is still there and that the stack grows
through it, also after a PROT_NONE protect of its lowest page. The debt
file records that those pages come in read/write as the stack grows.
2026-10-15 08:10:42 -07:00
Adrià d67b79a7e4 Merge pull request #5709 from fogydes/fix/libc-formatting-allocation-and-bounds
fix(libc): check allocation result in vasprintf and guard null pointer in strndup
2026-10-15 17:04:33 +02:00
Adrià 0e6a5e7a5c Merge pull request #5690 from SandstromPL/fix/savedata-mount3-invalid-dir-name
fix(savedata): return a parameter error from sceSaveDataMount3 for an invalid directory name
2026-10-15 17:04:04 +02:00
Adrià 162adb9da8 Merge pull request #5669 from MarcZX100/codex/signal-mask-128
fix(libkernel): honor all guest signal mask words
2026-10-15 17:03:59 +02:00
Adrià 8a253707e6 Merge pull request #5663 from al3w0f205/feat/libkernel-munlockall
feat(libkernel): add munlockall export
2026-10-15 17:03:54 +02:00
Adrià f5a55a11d0 Merge pull request #5662 from Roojool/contrib/g15-libc-pending
feat(libc): implement collate<wchar_t>::_Getcat
2026-10-15 17:03:49 +02:00
Adrià 9490a6da68 Merge pull request #5617 from Dripl1x/feat/socket-timeouts
feat(libkernel): apply SO_RCVTIMEO and SO_SNDTIMEO on a guest socket
2026-10-15 17:03:37 +02:00
Adrià 63b377b51b Merge pull request #5612 from JJenkx/feat/private-mutex-sharing
fix(libkernel): store mutex process-sharing attributes
2026-10-15 17:03:30 +02:00
Adrià 51b1d4a3a0 Merge pull request #5611 from JJenkx/fix/kernel-virtual-query-layout
fix(libkernel): stabilize virtual-query layout across hosts
2026-10-15 17:03:24 +02:00
Adrià 08290338aa Merge pull request #5599 from JJenkx/feat/libc-isfinitel
feat(libc): implement x87 long-double finite classification
2026-10-15 17:03:18 +02:00
Adrià b4a4fcac0e Merge pull request #5254 from 0xRickx/fix/libsceaudiodec-heaac
fix(libSceAudiodec): decode HE-AAC as the console does
2026-10-15 16:59:46 +02:00
Yunus Shaikh 668ecaeca2 fix(agc): fall back to pixel (0,0)'s sample locations where the device has no 2x2 grid
A draw whose sample locations vary between the pixels of the guest's
2x2 pattern threw "sample locations varying between pixels require a
2x2 sample location grid for the draw's sample count" on a device
whose maxSampleLocationGridSize for that sample count is not a
multiple of 2x2. An RTX 3070 Laptop GPU reports 1x1 for every count,
so Resident Evil Village's 2x checkerboard pattern stopped there
before its title.

The pipeline now decides the grid when it is created: such a pattern
is drawn through a 1x1 grid with pixel (0,0)'s locations, the first
registers of the pattern and the pixel the guest's grid is anchored
at, and the first such pipeline of each sample count logs it. The
render pass begin takes the pipeline's grid, so a sample-location-
compatible depth image is begun with the locations it is drawn with.
Devices with the grid keep it, and uniform patterns are unchanged.
2026-10-15 14:36:22 +00:00
Bruce Blake 873fbe99aa fix(libkernel): cap getdtablesize at the host descriptor table size
On macOS the RLIMIT_NOFILE soft limit is not a bound on the descriptor table: setrlimit accepts soft limits above kern.maxfilesperproc, RLIM_INFINITY included, and getrlimit reports what was set, so returning the guest soft limit alone could report up to INT_MAX for a table of about 122880 descriptors, and a closefrom-style loop up to that value would run billions of iterations instead of about 122k. Return the smaller of the guest soft limit and the host's ::getdtablesize(), which is the FreeBSD sys_getdtablesize result. The guest test derives its expectation from the host call instead of the implementation's formula, and the debt entry no longer claims the limit is raised when libkernel loads outside Linux. Reported by jotitadev in review of the getdtablesize implementation.
2026-10-15 10:35:04 -04:00
JJenkx c2f375fb63 feat(libkernel): convert guest POSIX error values 2026-10-15 10:34:39 -04:00
Adrià ff23657f34 Merge pull request #2852 from alfalfa-star/feat/np-user-id-by-account-id
feat(npmanager): implement sceNpGetUserIdByAccountId
2026-10-15 16:34:37 +02:00
Adrià f7bc3732e0 Merge pull request #5712 from ErenYeager1836/fix/msgdialog-native-error-codes
fix(libSceMsgDialog.native): return error codes instead of throwing in initialize and terminate
2026-10-15 16:34:28 +02:00
capmare 2be7b0769a feat(libSceFontFt): implement the font format support exports 2026-10-15 16:30:32 +02:00
MarcZX100 99d4d230a9 docs(dev): sync trace switches with current code 2026-10-15 14:29:57 +00:00
MarcZX100 6603a9d096 docs(dev): list tracing environment switches 2026-10-15 14:29:10 +00:00
billythemenace2andClaude Opus 5.5 01d3594c20 fix(agc): treat a TYPE 1 T# in a read-only static image slot as null
A static, read-only image slot whose T# has TYPE 1 is now bound as a null
image, like TYPE 0 since #5473 and #4779. On gfx1010, image_sample_lz,
image_sample_b, image_load and image_get_resinfo through a format-22
TYPE 1 T# return zeros without a fault, and gfx1035 reads it as zeros
too. Written, atomic and table slots still throw, and the reserved
types 2-7 stay refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-15 15:16:56 +01:00
Nixitov 443df0551b feat(libkernel_sys): implement fchown
Morrowind imports fchown and stops at it once rtprio_thread and the pthread concurrency controls are in. Accept the guest's own owner and group (0) or unchanged (-1), fail an invalid descriptor with EBADF, and throw for another owner or group, since ownership is not modelled.
2026-10-15 16:02:36 +02:00
Adrià 0dab493f5b Merge pull request #5816 from Nawasfadili/feat/libc-wide-and-unlocked-stream-io
feat(libc): implement wide and unlocked stream I/O
2026-10-15 15:58:44 +02:00
Adrià 56f5a6eef7 Merge pull request #5757 from hypermoist/perf/vector-window-unindexed-slots
perf(recompiler): keep the vector window's unindexed slots out of the array
2026-10-15 15:58:23 +02:00
Adrià 5c0cc1bba4 Merge pull request #5755 from AlexOfTheForest/fix/decoder-rip-far-indirect
fix(relinker): report RIP-relative operands of far indirect CALL and JMP
2026-10-15 15:58:16 +02:00
Ondra97 65e95f7139 fix(libkernel): serialize Windows vectored file transfers 2026-10-15 15:48:10 +02:00
Adrià Franch 04b1e9b0b7 fix(libSceIme): reuse ErrorBusy for duplicate keyboard open and record the behaviour in technical debt 2026-10-15 15:45:56 +02:00
Nithishvelan M 5e2e135280 fix(libSceSaveDataDialog.native): validate dialog state in close, get result and terminate 2026-10-15 19:14:21 +05:30
Yunus Shaikh 4344c1dc29 Merge branch 'main' into perf/shader-direct-cpu-evaluable-images 2026-10-15 06:38:09 -07:00
pushkarreddyy fd90df41b6 feat(libSceAgc): implement sceAgcGetDefaultCxStateFlat 2026-10-15 15:36:43 +02:00
simonbronkandClaude Opus 5.5 63db31fdd1 fix(shader): read explicit-LOD and level-zero 2D-array samples through 1D T#s as measured
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 15:36:02 +02:00
Crimson b0c283daa8 docs(build): note Bitdefender Advanced Threat Defense hanging guest_raise_exception 2026-10-15 16:32:09 +03:00
MrMha aea1dd601a feat(libc): provide the runtime scripting allocator hooks
Use the registered application allocator and the source-backed alignment/size signature. Add callback ownership and failure checks; record unmeasured console behavior.
2026-10-15 17:21:14 +04:00
Adrià FranchandClaude e0b9572e3b ci(windows): find the CA bundle of Git for Windows under ucrt64 too
Git for Windows 2.56 (runner image 20261002) moved from mingw64 to ucrt64,
so the fixed SSL_CERT_FILE path no longer exists and the WinLibs CMake
fails the FFmpeg download with status 60 on every Windows build. Take the
bundle from whichever of ucrt64 and mingw64 exists.

Co-Authored-By: Claude <[email protected]>
2026-10-15 15:20:44 +02:00
hugodearaujo e8b7361a1c fix(agc): settle dma-buf imports on Linux on the settle queue
The kernel maps a dma-buf import's pages for the GPU at the first submission that uses it. On RADV
that took about 2 s for a 3 GiB import, in the second frame of Hades (PPSA03355), and its staging
pool ran out while the frame was held.

Linux now makes the settle queue from #6060 when the device imports dma-buf memory, and settles
every dma-buf import of 1 MiB or more right after it is made with settleImport's 4-byte copy. The
settle queue needs neither the GPU mutex nor the main queue's work to finish. A dma-buf import's
buffer is shared with the settle queue's family instead of aliased, since a sparse import is bound
to many memory objects. Where the sparse queue already takes that family, the settle queue is a
second queue of it.
2026-10-15 10:19:46 -03:00