Commit Graph
12196 Commits
Author SHA1 Message Date
Dean 3357199fce Merge pull request #243 from adriadam10/feat/audio-in-capture
feat(libSceAudioIn): capture from the host's recording device
2026-10-04 19:55:15 +13:00
Adrià FranchandClaude fe26911cbb fix(shader): build f32/f64 conversion NaNs from the bits
OpFConvert leaves NaN payloads to the driver; NVIDIA returns its own.
v_cvt_f64_f32 now shifts the f32 payload left by 29 and v_cvt_f32_f64
keeps the top 23 payload bits, both quieted, as RDNA does (60/60 NaN
conversions measured on RDNA2). F64NanConversions covers both with the
hardware rows.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:52:14 +02:00
Adrià FranchandClaude 6ea9750bf3 refactor(shader): read f64 operands through readF64Bits and record the v_fma_f64 subnormal gap
Co-Authored-By: Claude <[email protected]>
2026-10-04 08:52:14 +02:00
Adrià FranchandClaude 6f20ed3778 fix(shader): compute v_fma_f64 exactly instead of relying on the driver
The Vulkan precision table defines GLSL.std.450 Fma as "inherited from
OpFMul followed by OpFAdd", so a driver may round twice. RADV fuses it,
the lavapipe in CI (Mesa 25.2.8, LLVM 20) does not, and F64Arithmetic
failed there on the fma rounding-error row.

v_fma_f64 is now emulated with operations Vulkan requires to be
correctly rounded: the operands are scaled to exponent 0, the product is
split exactly (Dekker), added to the addend with TwoSum, the low parts
are summed with round-to-odd and one final round-to-nearest gives the
fused result (Boldo and Melquiond). The result is scaled back by two
exact powers of two. Inf/NaN, zero factors and subnormal inputs take the
mul + add path, an addend 2^60 larger than the product is returned as
is. Matches the hardware on all 13253 fma results captured for #446 and
an exact model on 300000 random inputs incl. ties.

NaN results of add, mul and fract are also chosen on the bits (first NaN
input quieted, otherwise the default NaN) since Vulkan does not specify
which NaN an operation returns.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:52:14 +02:00
Adrià FranchandClaude b0afa04c77 feat(shader): implement basic f64 VALU ops
Decode and translate v_add/mul/fma/min/max/ldexp_f64, v_trunc/ceil/floor/
rndne/fract_f64, v_frexp_mant/exp_i32_f64 and the f64 <-> f32/i32/u32
conversions. f64 values stay as their raw bits (U64) in the IR and are
bitcast to double in SPIR-V, which needs the Float64 capability: the
device enables shaderFloat64 when it also preserves signed zero, inf and
NaN for 64-bit floats, and the shader declares SignedZeroInfNanPreserve 64.

Semantics measured on RDNA2 hardware (8209 inputs per op): literals are
the high dword, the 1/(2*pi) inline constant is the exact double,
omod is ignored, clamp maps NaN to +0, min/max quiet a
signaling NaN and drop a quiet one, NaN results are quiet, and the
integer conversions saturate with NaN -> 0. Truncation, rounding and
ldexp are done on the bits so they do not depend on the driver: lavapipe
returned wrong results for f64 RoundEven and Trunc, and GLSL Ldexp is
undefined past +-1024. Fma is NoContraction so RADV keeps it fused.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:52:14 +02:00
Dean Galvin b6298bf738 fix(agc): keep one storage image for a surface viewed past its last mip
The descriptors of one surface share its storage image through the
surface key, which includes the level count. A view past MAX_MIP
counts the extra levels, so its storage image was a second image of
the same memory, and the two flushed and re-uploaded each other every
frame (PPSA21564 writes level 6 of each 1920x1080 bloom chain after
building levels 1 to 5 through MAX_MIP 5 views).

A surface once viewed past its allocated levels now keeps a single
image holding the extended chain, and its other descriptors look that
image up; the allocated-level image it replaces is evicted with its
results stored. The extra levels lie in the allocation (the decode
proved that), so levels 0 to MAX_MIP keep their layout and the views
of them read the same texels.
2026-10-04 19:52:04 +13:00
Dean Galvin 3d3e687971 fix(agc): address texture views that start past the surface's last mip
PPSA21564 ends each of its two 1920x1080 RGBA16F bloom downsample
chains (MAX_MIP 5) with a compute pass that stores level 6 through a
view of levels 6..6, every frame from the PS logo on. The descriptor
decode threw for such a view.

GFX10 uses MAX_MIP only to place the levels: a level's address comes
from the levels below it, and a level in the mip tail is a fixed slot of
the tail block counted from the first tail level. A level past MAX_MIP
is addressed the same way, so when the chain extended to the view's last
level keeps every allocated level, the tail and the surface size
unchanged, the view reaches that slot inside the surface's allocation.
addrlib (GFX10, Navi10 with 16 pipes) computes the same 0x1640000-byte
layout for 6, 7, 9 and 11 levels of this surface, with level 6 in the
tail at (0, 32). The view then decodes with the extended chain over the
same guest bytes. Views whose extra levels would move the allocated
ones, such as linear chains or chains without a tail, still throw.
2026-10-04 19:52:04 +13:00
Dean b0a4a991cb Merge pull request #334 from adriadam10/feat/ds-permute
feat(shader): implement ds_permute_b32
2026-10-04 19:42:21 +13:00
Dean dda274b5e7 Merge pull request #434 from adriadam10/feat/relinker-sha256-memory
feat(relinker): lower SHA-256 instructions with a memory operand
2026-10-04 19:42:10 +13:00
Dean ec720a351c Merge pull request #437 from adriadam10/feat/vop3-qsad-mqsad
feat(shader): implement v_qsad_pk_u16_u8, v_mqsad_pk_u16_u8 and v_mqsad_u32_u8
2026-10-04 19:41:53 +13:00
Adrià FranchandClaude 7e5ce945e1 feat(libSceAudioIn): implement sceAudioInClose and throw for the unverified 0x10 format
Close releases the port and its host device; Input and Close on a port
that is capturing return BUSY. Format codes follow the PS5 SDK bindings
(SharpProspero) and KytyPS5: 1/2 S16 mono/stereo, 0x11/0x12 float.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:39:33 +02:00
Adrià FranchandClaude 29aa4f3cdf feat(libSceAudioIn): capture from the host's recording device
sceAudioInOpen validates the port and opens the default SDL recording
device in the requested format; sceAudioInInput returns one grain of
captured samples, padded with silence when the device falls behind and
keeping at most four grains of latency. Without a recording device a
port reports DEVICE_NONE in sceAudioInGetSilentState and delivers
silence at its sample rate.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:37:09 +02:00
Adrià FranchandClaude eff7af93d4 fix(shader): translate s_setreg_imm32_b32 only for round to nearest even in MODE
Any other field or value throws. The existing s_setreg_b32 no-op is
recorded under Functional technical debt instead of silent stubs.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:28:52 +02:00
Adrià FranchandClaude f994cc6ab7 feat(shader): implement s_cmovk_i32, s_version and s_setreg_imm32_b32
s_cmovk_i32 writes the sign-extended 16-bit immediate when SCC is set.
s_version is a no-op marker. s_setreg_imm32_b32 takes its value from a
literal dword and is ignored like s_setreg_b32; both are now listed as
silent stubs in TechnicalDebt.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:26:58 +02:00
Dean Galvin be3f06bfe8 feat(libSceAudioPropagation): render silence for propagated sources
sceAudioPropagationSourceRender takes the system, an array of RenderInfo
descriptors and their count: PPSA21564 and PPSA21567 pass one RenderInfo
{0x010107d6, 0x30} per call, with the source handle at +0x10, its output
buffer at +0x18, the buffer size in bytes at +0x20 and the word 2 at
+0x28, once per audio grain for each propagated source.

Without acoustic propagation a source contributes nothing, so each
output buffer is zeroed for its size. Every RenderInfo is checked first
(descriptor, a live source of this system, a non-empty output), and a
count of 0 or a format word other than 2 throws, as neither has been
observed.
2026-10-04 19:26:06 +13:00
Adrià FranchandClaude 01bae4dd79 fix(shader): track the multi-register destinations of the quad SAD ops in vertex fetch analysis
Co-Authored-By: Claude <[email protected]>
2026-10-04 08:23:37 +02:00
Adrià FranchandClaude f9a074250f feat(shader): implement v_qsad_pk_u16_u8 and the mqsad ops
Decode VOP3 0x172, 0x173 and 0x175. Each op slides a 4-byte window over the
64-bit src0 and adds the byte SAD against src1 to the matching 16-bit
(pk_u16) or 32-bit (mqsad_u32) field of src2; the mqsad forms skip zero
reference bytes. Sums wrap per field, as measured on RDNA2 hardware.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:22:25 +02:00
Adrià FranchandClaude 5fc16a9548 feat(relinker): lower SHA-256 instructions with a memory operand
SHA256RNDS2/MSG1/MSG2 with a memory source made `--to-intel` fail the
whole relink. The stub now spills a scratch xmm, loads the operand into
it with MOVDQU (AMD does not fault on a misaligned SHA operand, so the
unaligned load keeps that behaviour) and runs the register-form
lowering. RSP-based operands get the spill depth added to their
displacement. RIP-relative operands still fail: the stub runs at a
different address.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:21:40 +02:00
Adrià FranchandClaude 13ac232520 fix(shader): count ds_permute_b32 as a lane source
With uniform inputs every lane writes to the same target lane, so only
that lane receives the value; the two-lane wave64 path must not share it.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:21:33 +02:00
Adrià FranchandClaude dbb76aa511 feat(shader): implement ds_permute_b32
ds_permute_b32 is the forward (scatter) counterpart of ds_bpermute_b32:
every active lane sends its data to lane ((addr + offset) >> 2) & 31 of
its wave. As measured on hardware, the highest sending lane wins, an
active lane nobody writes to gets 0 and inactive lanes neither send nor
receive. It lowers to one shuffle of the data, address and EXEC bit per
source lane, using the same wave base as ds_bpermute_b32.

Co-Authored-By: Claude <[email protected]>
2026-10-04 08:19:43 +02:00
Adrià FranchandClaude 5c09d039bb perf(shader): index ValidateProgram by value and block id
Co-Authored-By: Claude <[email protected]>
2026-10-04 08:18:51 +02:00
Dean 870bdd814f Merge pull request #373 from MichonGoddijn231849/fix/replaced-device-shadows
fix(agc): a replaced device's unit shadows leave the registry
2026-10-04 18:49:42 +13:00
Dean a874079ac6 Merge pull request #422 from MichonGoddijn231849/perf/graphics-failure-memo
perf(agc): memoize source failures of draw stages as for compute
2026-10-04 18:49:25 +13:00
Dean 50eafda4ce Merge pull request #424 from MichonGoddijn231849/perf/template-rebind-moved-buffers
perf(agc): draw templates rebind moved read-only buffers and data words
2026-10-04 18:49:08 +13:00
Dean 7b64e262d8 Merge pull request #427 from RomainROCH/codex/fix-wide-string-precision
fix(libc): count wide string precision in output characters
2026-10-04 17:50:53 +13:00
Dean 2e9da3f0fa Merge pull request #350 from QDarkRex/fix/relinker-windows-icon
fix(relinker): add icons to generated Windows executables
2026-10-04 17:50:37 +13:00
RomainROCH a35e0cfc84 test(relinker): register segment coverage beside load alignment checks 2026-10-04 05:59:16 +02:00
RomainROCH 85d036ca19 perf(relinker): reuse each segment scan across import records 2026-10-04 05:37:13 +02:00
RomainROCH bd2223bba8 Merge remote-tracking branch 'origin/main' into codex/fix-executable-segments 2026-10-04 05:31:06 +02:00
RomainROCH 73d042321b Merge remote-tracking branch 'origin/main' into codex/fix-elf-string-bounds 2026-10-04 05:30:58 +02:00
QDarkRex d8684cb184 test(relinker): add C++ unit test for WindowsIconResourceBuilder 2026-10-04 10:29:20 +07:00
QDarkRex 9642d1b3b0 fix(relinker): add icons to generated Windows executables 2026-10-04 10:29:20 +07:00
RomainROCH 328def4bab fix(relinker): validate all executable segments and preserve live imports 2026-10-04 05:26:01 +02:00
RomainROCH e63524ae34 fix(relinker): bound dynamic strings by the declared table size 2026-10-04 05:23:18 +02:00
Dean Galvin 584c5bc590 perf(agc): wait for a pending key fill before materializing a register DCC clear
The first draw into a target whose DCC keys hold the register clear code
materializes the clear. The GPU clear of the resident image refuses while a
recorded write to the keys is still pending, so whenever the title's own key
fill had not run yet the clear went the CPU way: the clear texels stored
into guest memory (16 MiB for PPSA21564's normal G-buffer) and the image
uploaded again. With the occlusion dumps no longer draining the device, the
fill is usually still pending at that draw, and that was every frame of
PPSA21564's level.

The draw now waits for the recorded writes of the key range alone, checks
the keys again, and clears on the GPU when they still hold the register
code, as it did when the fill had already landed.
2026-10-04 16:17:09 +13:00
Dean Galvin 2596f8c0ad perf(agc): record occlusion counter dumps on the GPU
Every ZPASS_DONE counter dump drained the device so the CPU could add up
the occlusion queries of the finished batches and store the running total.
PPSA21564 dumps around each occlusion-tested pass: about 1.5k drains per
10 s at its title screen, and in a level's early passes four drains a frame
that took 5.6 s of every 10 s of the graphics worker.

The running total now lives in a small buffer the GPU updates in batch
order. A batch still ends its occlusion query at submit; a query that saw
draws is remembered, and its pool is kept alive until it is folded. A dump
ends the open batch's query, copies the remembered results next to the
total, adds them with a one-thread compute shader that also stores the 16
DB counters into the dump's host import, and begins a fresh query for the
rest of the batch. The dump is ordered with the work around it like any
other GPU store, noted as a pending write and stamped. More than 64
remembered results are folded at a submit. Query pools are recycled.

A dump into memory the GPU cannot see, under a pending copied write-back
or over a label the CPU stores at a completion falls back to the drain,
which settles the remembered results on the CPU. Without buffer device
addresses the counting stays on the CPU.
2026-10-04 16:17:09 +13:00
Dean 33a2f907f4 Merge pull request #460 from oneandonlydean/perf/agc-gpu-mesh-indirect
perf(agc): draw mesh-stage indirect draws on the GPU
2026-10-04 16:15:58 +13:00
Dean 2cb95dab12 Merge pull request #452 from SP4C3B4R-8/fix/scissor-window-offset
fix(libSceAgcDriver): accept scissors that apply the zero window offset
2026-10-04 15:48:01 +13:00
Dean Galvin fb55cb2c0e perf(agc): draw mesh-stage indirect draws on the GPU
A mesh program took its draw's index count from push constants, so an
indirect mesh-path (NGG) draw needed the CPU to read its record first,
waiting for the GPU to finish everything recorded before. In PPSA21564
that was about 170 waits per 10 s at the title, menu and level (about
1 s), and one per frame in the intro (2.2 s per 10 s).

The two free mesh push dwords now carry the device address of an argument
record (a VkDrawMeshTasksIndirectCommandEXT followed by the index count
and first index). When the address is set, the prologue takes the index
count and the first index from the record (the new MeshArgument IR value,
a load through a physical storage buffer pointer) and offsets its index
reads by the first index; a direct draw leaves the address 0 and draws as
before. Mesh modules declare the physical storage buffer capability for
it, and the driver's SPIR-V validation accepts the extension in mesh
modules.

An indexed mesh draw with one record that patches no user SGPR now stays
on the GPU. A one-thread compute pass (Graphics/shaders/MeshArguments.comp)
turns the record, read in place from its host import, into the draw's
argument record: the groups and instances of vkCmdDrawMeshTasksIndirectEXT
and the index count and first index the mesh program reads, with the CPU
path's rules (count clamped to the index buffer, nothing for an empty
record or past the device's group limits). The index buffer descriptor
covers the whole buffer and the program offsets by the first index. When
the records cannot be read in place, the CPU reads them and fills the
same argument record (ResolveMeshArguments).
2026-10-04 15:45:56 +13:00
Dean dca710d602 Merge pull request #465 from oneandonlydean/fix/agc-cross-queue-submission-order
fix(agc): run a wait-free submission of another queue after queue 0's earlier submissions
2026-10-04 15:45:30 +13:00
Dean 26e7783483 Merge pull request #457 from oneandonlydean/perf/shader-cache-version-inputs
perf(shader): hash only the recompiler's inputs into the shader cache version
2026-10-04 15:45:12 +13:00
Dean 2ccd3d7b56 Merge pull request #440 from oneandonlydean/feat/agc-fan-gs-input
feat(agc): take triangle fans as NGG geometry shader input
2026-10-04 15:44:54 +13:00
Dean 3e23099fbb Merge pull request #472 from adriadam10/fix/shader-memory-test-page-read
test(agc): keep shader memory test tables inside one guest page
2026-10-04 15:41:47 +13:00
Dean 0bd34077b4 Merge pull request #455 from arreina/pr/libatrac9-bounds
fix(audio): bound ATRAC9 decoding to the superframe
2026-10-04 15:41:29 +13:00
Dean 837bb8fe96 Merge pull request #438 from adriadam10/feat/vop3-div-fixup-f16
feat(shader): implement v_div_fixup_f16
2026-10-04 15:41:11 +13:00
Dean bbfb3c2b5c Merge pull request #242 from adriadam10/fix/nid-dynstr-suffix-sharing
fix(nid): share string suffixes when rebuilding .dynstr
2026-10-04 15:40:53 +13:00
RomainROCH 5211ba115b fix(libc): count wide string precision in output characters 2026-10-04 04:31:26 +02:00
Dean e006f64237 Merge pull request #284 from SP4C3B4R-8/fix/replaced-device-host-imports
fix(libSceAgcDriver): destroy host imports of a replaced Vulkan device
2026-10-04 15:13:54 +13:00
Dean e7eabe5048 Merge pull request #282 from SP4C3B4R-8/fix/vulkan-prefer-discrete-gpu
fix(libSceAgcDriver): prefer a discrete GPU over the first suitable device
2026-10-04 15:08:45 +13:00
Dean e84b558bf1 Merge pull request #462 from oneandonlydean/fix/agc-own-store-write-watch
fix(agc): consume the write-watch faults of the driver's own CPU stores
2026-10-04 15:01:48 +13:00