Commit Graph
7981 Commits
Author SHA1 Message Date
Adrià 7bb2b1f973 Merge pull request #5598 from JJenkx/fix/guest-declared-host-import-registry
fix(relinker): record declared host imports in guest registries
2026-10-15 13:58:59 +02:00
fdfawef324andClaude Opus 5.5 6a9b3d6fad docs(agc): record the BMP open failure measured on presentation
VideoOut flips on an RTX 3060 now show that a first frame dump that cannot be opened no longer stops presentation. Header, pixel and close failures remain measured only by the CPU fixture.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 07:56:13 -04:00
AlxcBTW 139e3b86ed fix(agc): route native-owned depth binds before the HTILE read and store-back
A multisampled depth target is created as, or already is, the native depth owner, and a target whose HTILE overlaps a resident depth guard aliases one. Neither may have its HTILE read or rewritten by the generic store-back: the expanded words would be a guest write over the owner's range. DepthSurfaceView decides this before the store-back, which still runs before GpuMutex() and the surfaces mutex are taken. NativeMultisampleDepth binds the owner and a single-sample alias of its HTILE and checks the words stay untouched.
2026-10-15 13:55:39 +02:00
hypermistandClaude Opus 5.5 f8b611b7da feat(libc): implement the compiler-rt floating-point builtins
Soft-float arithmetic and comparisons, float/double/x87 conversions to and from
32-, 64- and 128-bit integers, __extendsfdf2, __truncdfsf2, complex
multiplication and division and __powixf2, matching the libc.prx bundled with
PPSA08427: soft-float results ignore MXCSR and raise no flags, division flushes
subnormal quotients, NaN payloads are moved unshifted and float-to-integer
conversions do not saturate.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
2026-10-16 00:55:33 +13:00
Adrià 23dcb82499 Merge pull request #5648 from Amoenus/codex/buffer-resource-vcc-tuple
fix(shader): accept buffer resource tuples ending in VCC
2026-10-15 13:55:14 +02:00
Adrià Franch 0a7193b5cd fix(libkernel): sigsuspend swaps and restores all four mask words 2026-10-15 13:54:05 +02:00
AlxcBTW cc022df348 fix(agc): take a slice of a depth array from its own HTILE only when its words are uniform
A fill or clear the driver recognizes over an HTILE drops the range's last-read generation, so the
next bind reads the words and stores them back even when the write tracker did not see the fill's
stores. A depth view of slice 1 or later reads the HTILE at its own address
(DB_HTILE_DATA_BASE + slice * HtileMetadataBytes); the HTILE word layout is only modelled for slice 0,
so such a slice takes the clear and the store-back only when all its words are equal and keeps its
fill-time fast clears otherwise. DepthTarget::slice carries DB_DEPTH_VIEW SLICE_START.

agc_driver_depth_fast_clear_submit: an unrecognized kernel clears the HTILE on two frames in a row and
both clears are taken; slice 1 with words that are not all equal is refused and stored back untouched;
slice 1 with equal words takes the clear. agc_driver_graphics checks the decoded slice.
2026-10-15 13:53:50 +02:00
AlxcBTW 3e61fcf1f9 fix(agc): read and store back the whole pipe-aligned HTILE outside the surfaces lock
The bind-time HTILE read covered one word per 8x8 tile from DB_HTILE_DATA_BASE, but main models the
HTILE as the pipe-aligned SW_64KB_Z_X metadata (HtileMetadataBytes, the extent HtileFillCovers takes):
at 1920x1080, 1856 of the 32400 tile words lie past the first tiles*4 bytes, so they kept ZMask 0
after a store-back. The read and the store-back now cover the whole metadata and run before the
surfaces mutex is taken, since both wait for recorded work over the range. The tests' HTILE arrays
hold the whole metadata.

PPSA25344 (Unreal Engine 5) decodes its depth through HTILE in its Nanite depth export after the
depth prepass and takes ZMask 0 as a tile holding the clear value; the new
agc_driver_depth_fast_clear_submit case checks that a draw after a fast clear leaves every word
expanded.
2026-10-15 13:53:50 +02:00
esatturan 4ddff7c6e5 fix(agc): take depth fast clears from HTILE written by any kernel 2026-10-15 13:53:49 +02:00
aaroandCodex 5054b67b42 fix(relinker): preserve inputs behind Windows executable hard links
Co-authored-by: Codex <[email protected]>
2026-10-15 17:23:14 +05:30
hypermistandClaude Opus 5.5 667e8ad80c fix(libc): count zero bits of zero like the console's __clz and __ctz builtins
The libc.prx bundled with PPSA08427 returns 32 from __clzdi2 and __ctzdi2 and
64 from __clzti2 and __ctzti2 for a zero argument; found by comparing every
builtin against it on random inputs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
2026-10-16 00:51:46 +13:00
Adrià fdea36b836 Merge pull request #5524 from Amoenus/codex/native-depth-allocation-retirement
fix(agc): retire fully released native depth owners
2026-10-15 13:50:13 +02:00
Adrià FranchandClaude a8be2c8fee docs(ngs2): matrix levels debt line names the voice-without-format exception
Co-Authored-By: Claude <[email protected]>
2026-10-15 13:49:09 +02:00
milescovielloandClaude Opus 5.5 c6e3af3258 fix(ngs2): accept empty waveform blocks and matrix levels on a voice without a format
A sampler voice set up with an all-zero format has no channels. Adding no
waveform blocks to it, or setting a matrix with no levels, threw
std::invalid_argument, which ends the title.

Accept both on such a voice: the empty add only applies RESET and the
CONTINUE state, and the empty matrix clears that matrix, which rendering
already treats as unset. Blocks with data, APPEND, and an empty matrix on
a voice with a format are still refused.

Steins;Gate Re:Boot (PPSA36591) clears a voice this way when a button is
pressed at its title screen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 13:48:54 +02:00
fdfawef324andCodex 6541db004b fix(agc): disable optional BMP dumps after host I/O failures
Use checked host stdio for BMP output and stop requesting dumps after the first write failure. Keep pixel validation, allocation and non-I/O failures on the existing fatal path.

Co-Authored-By: Codex <[email protected]>
2026-10-15 07:39:36 -04:00
Adrià 38d2454486 Merge pull request #5559 from JJenkx/fix/guest-executable-import-dependencies
fix(relinker): select guest startup dependencies from required roots
2026-10-15 13:38:52 +02:00
Adrià 5050a23f38 Merge pull request #5473 from MarcZX100/type0-recompiler-followup-4779
fix(shader): accept TYPE=0 images during materialization
2026-10-15 13:37:52 +02:00
KernelPanicNTandClaude Opus 5.5 5b7e3aea8b feat(libSceAmpr): implement __cxa_call_unexpected
__cxa_call_unexpected takes the in-flight exception's unwind header and
never returns, as in libcxxabi. No std::set_unexpected is exported and
the exception header's unexpected handler is never set, so the handler
is always the default one, which calls std::terminate. It therefore
forwards to libc's __cxa_call_terminate, which begins the catch and runs
the current terminate handler; a null header terminates in libc's
__cxa_begin_catch. libcxxabi's std::terminate would instead run the
terminate handler saved in the exception header at throw time; the two
differ only if std::set_terminate was called in between, which the debt
entry records.

The test shares the forked-child helper of the std::_Pad test, which now
takes the terminate handler to install.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 11:31:15 +00:00
hypermistandClaude Opus 5.5 0d62d4ee1a feat(libc): implement the compiler-rt integer builtins
Shifts, bit counts, comparisons, negation, multiplication, division and
remainder, __udivmodti4, the overflow-reporting __mulo* and the overflow
checking __addv*/__subv*/__mulv*/__negv*/__absv* families. Where the libc.prx
bundled with PPSA08427 differs from compiler-rt it is followed: __addv* and
__subv* wrap, and the 32-bit unsigned division returns 0 for a zero divisor.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
2026-10-16 00:30:58 +13:00
Adrià 5e7d09aafe Merge pull request #5538 from JJenkx/fix/ngs2-render-capacity
fix(ngs2): limit render writes to the configured grain
2026-10-15 13:29:33 +02:00
Adrià 821c69e504 Merge pull request #5509 from billythemenace2/fix/shader-cube-tsharp-2d-access
fix(shader): read cube T#s through DIM 2D image_sample and image_load as face 0
2026-10-15 13:25:34 +02:00
Adrià 39d3ae13eb Merge pull request #5304 from tv7/fix/stencil-ref-export-unused
fix(agc): drop an unused stencil test value export from draws without a stencil test
2026-10-15 13:24:56 +02:00
CapibaraandClaude Sonnet 5 efd5596008 docs(libSceRegMgr): record signature provenance in technical debt
Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-10-15 08:14:37 -03:00
hypermistandClaude Opus 5.5 7d7515b632 docs(debt): drop the call tracing entry that --trace-imports superseded
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 00:14:25 +13:00
Adrià FranchandClaude 91878f51f9 docs(debt): describe the TYPE=0 null image scope as implemented
Co-Authored-By: Claude <[email protected]>
2026-10-15 13:12:00 +02:00
Yunus Shaikh a34ba0c7c7 Merge branch 'main' into perf/shader-direct-cpu-evaluable-images 2026-10-15 03:54:08 -07:00
Adrià Franch 6f0aa97f6c docs(debt): describe the unused stencil export drop next to the stencil replay 2026-10-15 12:51:37 +02:00
NikoandClaude Opus 5.5 c434467f6c fix(agc): form reversed-order blend factors from copies of the export
The reversed-order blend computed the factors Vulkan cannot apply per
channel in the pixel shader (1 - x in fp32, a clamp for UNORM targets
and, when both positions needed it, a premultiplied export) and passed
them to the blend as a dual-source second color. A plain blend converts
the export once and forms 1 - x and the products from that converted
value, so the two paths can round differently. On UNORM8 the difference
reaches one step per substituted factor: an Intel iGPU stored 161 where
the exact blend is 159.75 for SRC_COLOR + ONE_MINUS_SRC_COLOR with an
export of 0.5 over 192 (160 through SWAP_STD), and on an RTX 5080 and
lavapipe the split path differed from the same draw into a SWAP_STD
target by up to 2 steps on other inputs.

The pixel shader now only copies values. Each channel of the second
color is the exported alpha, the channel's own export or the constant 0
or 1, and a channel of the first color whose source factor is ONE may
become 1 with its export moved into the factor. Every factor, 1 - x and
product comes from the blend through SRC1_COLOR, SRC1_ALPHA and their
ONE_MINUS forms, applied to copies of the same export values that the
first color carries. TranslateReversedBlend searches for Vulkan factors
and copy routes that reproduce each channel's guest factors and throws
for combinations no routing reproduces, such as ONE_MINUS_SRC_ALPHA in
the alpha equation next to SRC_COLOR in the color equation: of the 1995
factor combinations the shader used to compute, 932 are routed and the
others throw again, as on main. GT7's 0x65010504 is among the routed
ones. The code is now four 2-bit routes for each color, the same for
every format, and the post-pass emits no arithmetic.

agc_driver_reversed_order_blend also draws each case into a SWAP_STD
target, which Vulkan blends alone, and requires identical stored bits;
the comparison with the exact blend keeps its 1-step tolerance.
agc_driver_graphics checks every factor combination TranslateReversedBlend
accepts against the guest equations and that the post-pass adds no
arithmetic instructions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:51:27 +02:00
NikoandClaude Opus 5.5 16ea32c97d feat(agc): blend into color targets with a reversed component order
8_8_8_8 and 16_16_16_16 targets with COMP_SWAP 2 or 3 keep the exported
alpha in their first channel and red or blue in their fourth, so a plain
Vulkan blend would run the alpha equation on a color channel. Such draws
threw "blending into a color target with a reversed component order is
not implemented" (Gran Turismo 7, #4782).

The AMD SI and CIK register references describe CB_TARGET_MASK in the
order of components after blending and before COMP_SWAP is applied, and
RADV programs CB_BLENDn_CONTROL without regard to the swap while it
renders R4G4B4A4, B4G4R4A4, R5G5B5A1 and B5G5R5A1 through SWAP_STD_REV
and SWAP_ALT_REV and passes the CTS blend tests on Navi10. The color
block is therefore taken to blend in export order: the alpha equation
and source-alpha factors use the exported alpha and the destination
alpha is the first channel.

TranslateReversedBlend keeps the factor pairs Vulkan applies per channel
in the pipeline. Other source factors are computed by the pixel shader
from its MRT0 export (clamped for UNORM targets, as BLEND_CLAMP says)
and handed to the blend as a dual-source second color, which the
fragment output post-pass adds at location 0 index 1; when both
positions need it, the export is premultiplied by its source factor.
The code is a pipeline specialization, serialized in request version
26, and stays out of the prepared shader key.

sRGB, SNORM and integer targets, constant and second-source factors,
destination alpha in the color equation, destination factors the two
equations do not share, different color and alpha operations, MIN or
MAX with factors other than ONE, other color exports when the shader
computes factors, and devices without dualSrcBlend still throw, now
with the blend control, mapping and format in the message.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:51:27 +02:00
Yunus Shaikh 0b099964f0 Merge branch 'main' into perf/shader-direct-cpu-evaluable-images 2026-10-15 03:19:52 -07:00
Adrià FranchandClaude 03401459f9 perf(agc): pipelined draws and exact draw write ranges on by default
Queue 0 now pipelines draw commits unless APS5_PIPELINED_DRAWS=0, and draw write ranges use the exact
color, DCC, CMASK, depth and stencil sizes unless APS5_EXACT_DRAW_WRITES=0. The base tests now run the
pipeline; agc_driver_pm4_failure_inline and agc_driver_draw_cache_reuse_inline keep the inline path
covered.

Co-Authored-By: Claude <[email protected]>
2026-10-15 12:13:26 +02:00
Romans Pokrovskis da9fe3c708 fix(agc): retire fully released native depth owners
Track successful releases cumulatively across the complete depth and HTILE ownership ranges. Preserve color retirement and share its single callback; keep retired image contents alive through sampled views and recorded work. Add registry, partial/failure/protection, remap and mixed teardown regressions. Depends on native depth sampling in PR5496 and its descriptor prerequisite PR4820.
2026-10-15 13:08:13 +03:00
Parth Bhanti c9d3ff87d9 fix(libkernel_sys): handle AT_SYMLINK_NOFOLLOW natively on macOS and document silent stub 2026-10-15 03:04:18 -07:00
Adrià FranchandClaude 4051ee19c5 docs(architecture): describe the queue-0 draw pipeline
Co-Authored-By: Claude <[email protected]>
2026-10-15 11:34:29 +02:00
Yunus Shaikh 896b737700 fix(libSceNet): keep one receive timeout across the wait for a local address
When the address came during the wait, the host receive that followed
waited its whole SO_RCVTIMEO again, so a receive could take up to twice
the timeout. FreeBSD's soreceive_dgram sleeps once per timeout. Now the
receive waits for a datagram with WSAPoll only for what is left of the
timeout, and fails with EAGAIN when it runs out, as before. Nothing
changes when the socket already had an address or has no timeout.
2026-10-15 02:34:12 -07:00
Santhosh Kumar 27b196bee0 fix(shader): preserve pixel helper lanes in EXEC copies
Expand the host active-lane mask to whole quads for pixel-stage EXEC value reads so saving and restoring WQM does not drop derivative inputs. Keep the existing host-lane mask in other stages. Add a GPU regression for implicit mip selection after an EXEC save/restore, across wave32/wave64 and native/emulated barycentrics.
2026-10-15 14:42:26 +05:30
eljackjoestar-cmd 6575aa217d fix(audio): retain completed AudioOut2 grains until pushed 2026-10-15 13:06:45 +04:00
SP4C3B4R-8andClaude Opus 5.5 626cff7d26 fix(libSceAgcDriver): retire a depth surface once another writer covers its memory
A depth surface lives only in its Vulkan image, so a view of its memory
with another layout could only throw, and a matching view kept reading
the image after other writes over its memory. Retire the surface when a
color target or a written storage image it does not serve overlaps its
planes, or when a view it cannot serve finds guest memory over the planes
written since the surface was last bound; lookups then skip it and the
view reads the memory like any texture. Binding the target again brings
the surface back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 11:00:36 +02:00
Adrià 0afa6a607e Merge pull request #6060 from parl0v/feat/watched-private-imports
perf(agc): keep Windows host imports of write-watched private memory watched
2026-10-15 10:54:43 +02:00
Adrià c4f03522a7 Merge pull request #5496 from Amoenus/codex/native-msaa-depth
feat(agc): sample native multisampled depth attachments
2026-10-15 10:54:18 +02:00
Yunus Shaikh a9c2717fd0 fix(libSceNet): return 0 from an unbound datagram receive after shutdown or for zero bytes
On Windows a receive on a datagram socket with no local address waits
for one. A sceNetShutdown of the receive side now ends that wait, and
later receives return 0 at once; a zero-length receive returns 0 without
waiting. FreeBSD's soreceive_dgram returns 0 in both cases. Before, a
thread blocked in such a receive kept waiting after the socket was shut
down.
2026-10-15 01:54:10 -07:00
Yunus Shaikh fe56f60561 fix(shader): bind a T# whose record the CPU evaluates directly when a table cannot express its operation
An image table cannot store, update atomically or read PCK and BY2/BY4
through its records (#757): those operations fault and read zeros. #6243
turns a heap T# whose words and record offset the SRT walker evaluates
into a selected one-record table, which kept that limitation although
such a T# is one known descriptor, as #5188's direct images were.

PlanTableColumns now binds such a T# directly, for every operation of the
shader on it, when any of them is a store, an atomic, a packed or a
BY2/BY4 access. A T# keyed per lane, or by a value the walker cannot
evaluate, keeps its table and its unsupported-operation fault. The disk
format moves to 37 so that plans cached by #6243's builds are not reused.
2026-10-15 08:50:15 +00:00
Yunus Shaikh 17ccfc497c perf(shader): walk a changed table column from the words its compare read
A kept column the runtime cannot vouch for is read and compared with its kept words. When they
differ, the fresh walk read the same runs again, so a capture that follows every change to a table
read each word twice: 1,048,576 words per capture for a 65,536-record column, 12% slower than
before the reuse with the write watch and 16% slower outside it.

The compare now leaves its words with the snapshotter, and the fresh walk takes them instead of
reading when its plan has the same runs: words the capture has already read read the same again.
Such a capture reads each word once, as before the reuse, and the 65,536-record column costs 7%
(12% outside the write watch) more than before the reuse; the rest is keeping the column. With 16
distinct T#s it costs 5 to 8% less. agc_shader_table_snapshot_reuse expects a changed table to be
read exactly once per capture.
2026-10-15 08:10:51 +00:00
Yunus Shaikh 0431419d16 fix(agc): store pending GPU results before vouching for an unwritten table column
Every read and store through GuestMemory calls the flush hook first. Recorder's FlushForAccess waits
for recorded GPU work over the range, records a queued label that writes it, publishes the unit
shadows over it and stores the storage image results kept on the GPU for it. A storage image result
is stamped only when it is stored (its write-back's MarkWritten), so ShaderMemory's stamp and check,
which never read the column, could vouch for words a read would have replaced: the column skipped
its read and the snapshot kept the T#s from before the result.

stampWrites and unchangedSince now call GuestMemory::FlushGpuWrites over the range after the pending
write query and before the tracker, as a read does, and as the dispatch cache stores pending images
before it validates an entry. The stamp then covers what the flush stored, so the capture after it
skips the read again.

agc_shader_table_snapshot_reuse installs a flush hook that stores a new T# into the table on its first
call over it. Without the flush in unchangedSince the reused snapshot keeps the old T#; without the
one in stampWrites the next capture compares the table instead of skipping its read.
2026-10-15 08:10:51 +00:00
Yunus Shaikh b02c442bbb perf(shader): reuse an image table column's snapshot while its memory is unwritten
Every capture of a shader with an image table read every record of each column and looked each
record up among the snapshot's distinct descriptors. A 32,768-record column of distinct T#s cost
6.1 ms per capture here (2.3 ms with 16 distinct T#s), and Resident Evil Village's title captures
such columns on nearly every draw.

TableSnapshotter now keeps the last 16 column snapshots per thread (at most 4 Mi words in all,
least recently used first out), keyed by heap base and size, record shape and key count: the runs
it read, their words, each record's state and code, and the distinct T#s. A narrowed, selected or
pointer-indirect column, or one with an unmapped record, is not kept. A capture of a kept column
takes the codes and the distinct T#s from it with no per-record work. When they are the snapshot's
first words they are taken as they are, and the words index is built only if a later column needs
it, so the result is the snapshot a fresh walk would produce, codes and words order included.

The runtime gets three optional callbacks: stampWrites gives a stamp for a range before any of it is
read, unchangedSince tells whether nothing wrote the range since, and supplyWords hands words that
equal guest memory to the capture as read, so they stay in the captured regions the draw cache
compares. ShaderMemory implements them with the write tracker. The stamp is CollectWrites's
generation, refused when this ShaderMemory already fetched a page of the range or recorded GPU work
writes it. A range is unchanged while no block of it is stamped after the stamp (collected CPU
stores, the driver's Write, WriteChanged and StoreOwnBytes, MarkWritten for GPU writes into
imports), no recorded GPU work writes it and the guest allocation generation is the stamp's. When
every run is vouched for, the column is not read at all; otherwise its runs are read and the
snapshot is reused only when they are equal word for word.

The 32,768-record column now costs 0.48 ms per capture with no word read when unwritten, and about
0.9 ms outside the write watch. APS5_NO_TABLE_SNAPSHOT_REUSE=1 turns the reuse off. The [image-table]
profile line counts the reuses, and ResourceMaterializer::TableReuse returns them with the words the
snapshotter read.
2026-10-15 08:10:46 +00:00
LeandroLP23andClaude Opus 5.5 79d72b6836 fix(shader): kill demoted quad-mask pixels when the pixel program returns
A pixel that PA_SC_AA_MASK leaves uncovered is demoted to a helper
invocation so the covered pixels keep their derivatives. When the guest
exports under an EXEC mask that clears that lane, the colour output is
never written. On the Radeon 860M (Windows driver 32.0.13058.8001) such
a demoted invocation still writes undefined colour to the target, so
agc_driver_quad_pixel_mask fails at its first implicit-LOD sample under a
partial mask (2). Killing the uncovered invocations at the return, after every
derivative is taken, discards them on every driver.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 10:09:52 +02:00
Adrià db81992c55 Merge pull request #5238 from MarcZX100/fix/trace-draw-program-addresses-5166
feat(agc): trace shader addresses for each draw
2026-10-15 10:06:31 +02:00
Adrià FranchandClaude 290be56265 test(agc): skip the dma-buf import probe when /dev/udmabuf can't be opened
Co-Authored-By: Claude <[email protected]>
2026-10-15 10:05:09 +02:00
Yossi Yadgar 39575d66e9 docs(debt): note which register-defaults table and type layout libSceAgc returns 2026-10-15 11:04:54 +03:00
Adrià FranchandClaude 23fccd7632 fix(agc): settle only imports of 1 MiB or more
Co-Authored-By: Claude <[email protected]>
2026-10-15 09:58:21 +02:00