Commit Graph

245 Commits

Author SHA1 Message Date
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à 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
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
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
Dextroid17 b7e32b3648 fix(shader): decode the scalar aperture sources 235-238 instead of failing the shader 2026-10-10 06:57:12 -04: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à 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à 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à 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
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à 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
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
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
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
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
arcwiser 3058b5193b fix(shader): name unsupported MIMG opcodes 2026-10-09 12:43:37 +11: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
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
Adrià ae91d9780b
Merge pull request #697 from queeeef/feat/interp-f16
feat(shader): implement v_interp_p1ll_f16, v_interp_p1lv_f16 and v_interp_p2_f16
2026-10-08 23:56:17 +02:00
Daan Dehing daa6bee7cf feat(shader): implement v_interp_p1ll_f16, v_interp_p1lv_f16 and v_interp_p2_f16
Decode the three VOP3 16-bit interpolation instructions (attribute, channel
and high-half select in the src0 field, the I/J VGPR in src1, P0 or the first
step's result in src2) and translate them with a new
GetInterpolationParameterF16 IR value. It reads the selected 16-bit half of
each vertex's parameter through VK_KHR_fragment_shader_barycentric, so P10 and
P20 are vertex differences rounded to f16; both steps are a multiply and an
add, as in the f32 forms.

An input in FP16_INTERP_MODE whose low half is defaulted is still declared at
its slot when its high half is read, and the high half takes its default from
USE_DEFAULT_ATTR1 and DEFAULT_VAL_ATTR1. Without barycentrics, on an input
without FP16_INTERP_MODE or on a pass-through input the instructions throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:36:04 +02:00
Claude c0519cc814 feat(shader): implement the 32-bit DS src2 operations
The decoder threw on the GFX10.1 DS src2 opcodes 0x80-0x8b, 0x8d,
0x92, 0x93 and 0x95. Each reads DS[B], where B is the address plus
four times the 15-bit signed offset in offset1[6:0]:offset0, and
applies the matching operation to DS[A]: add, sub, rsub, inc, dec,
signed and unsigned min and max, and, or, xor, f32 min, max and add
through the 32-bit LDS atomics, and a plain write for
ds_write_src2_b32. The form that takes the offset from the address
bits (offset1[7]), the 64-bit forms and GDS still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:06:15 +02:00
Adrià Franch 57d4be33bb feat(shader): implement MIMG PCK2/PCK4 loads as measured on hardware
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-08 21:54:10 +02:00
Adrià Franch d5a3a4321c fix(shader): follow measured hardware for MIMG BY2/BY4 loads
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-08 21:28:22 +02:00
Petre 88f7a5e0e4 feat(shader): lower full-width MIMG BY2 and BY4 transfers 2026-10-08 21:10:51 +02:00
Adrià Franch 7f25d49fb8 fix(shader): fetch packed horizontal gather texels and cover edge coordinates
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-08 20:42:14 +02:00
Mark Kuebel d0551d381b feat(shader): implement image_gather4h_pck end to end
Decodes IMAGE_GATHER4H_PCK (MIMG opcode 98) and IMAGE_GATHER8H_PCK
(opcode 99), implements gather4h_pck through translation, the SPIR-V
backend and a GPU execution test, and documents gather8h_pck as a
desktop null-op.

Semantics were measured on gfx1031 hardware with hand-encoded MIMG
words (LLVM rejects the PCK gather mnemonics on every RDNA1/RDNA2
target). The measured rule for gather4h_pck: the four-texel horizontal
window is floor(u*width-0.5)+{-1,0,+1,+2} clamped to the width, the row
is floor(v*height) clamped, the raw bits of the window texels are
concatenated into a little-endian bitstream (texel k at bit offset
k*texelBits), and output register j - the j-th set DMASK bit in
ascending order - receives stream word j, zero past the end of the
stream. Exactly popcount(dmask) consecutive VGPRs are written from vdst
ascending; texels wider than 32 bits write zeros (hardware limit); rows
past the height read zeros; negative coordinates clamp to zero. The
window anchor matches the repo's existing PS5-validated HorizontalOffsets
rule, so this reuses the established convention.

The decoder accepts multi-bit DMASKs for these two opcodes only and
sizes their data span as popcount(dmask) (measured), unlike gather4h
which always writes four components. Translation carries the packed
flag through imageMemoryInfoFromInstruction; the SPIR-V emitter
reassembles the bitstream per lane with per-texel OpImageFetch and
byte assembly. D16 data throws until measured.

gather8h_pck never returns texel data on this hardware: across dmasks
0x1-0xFF including the upper nibble, RGBA8/RGBA16/RGBA32 formats, 1D/2D
and 3D descriptors, normalized and unnormalized sampling, sentinel-
prefilled destination registers confirm it only ever zero-fills
popcount(dmask) registers. It decodes but throws at translation.

The measured semantics and the gather8h_pck null-op are recorded in
docs/dev/TechnicalDebt.md.
2026-10-08 20:42:03 +02:00
Sanjaysrinivas ee0b1109f4 feat(shader): execute bounded S_CALL_B64
Reuse the prerequisite call-region analysis for signed relative calls, including callees after s_endpgm. Lower the saved link as shader base plus PC+4 and reject unsupported targets and call shapes.

Add decoder, IR, CFG and Vulkan execution regressions. Seven focused CMake tests pass; five layouts cover 15 dispatches and 3,200 output comparisons on lavapipe. Record ISA sources and native RDNA2/PS5 limits in TechnicalDebt.
2026-10-08 20:22:51 +02:00
ebosido444-ai c48e01977d feat(shader): implement s_swappc_b64 fetch-shader call
Decodes SOP1 0x21 s_swappc_b64 (link pair = pc + 4) and resolves its call/return pairing through the existing s_setpc_b64 path: static call regions in GraphBuilder and the vertex-entry fetch-shader call inlined from the parsed fetch-shader plan. s_call_b64 (SOPK 0x16) and s_rfe_b64 (SOP1 0x22) throw at decode. Unmodeled cases throw; see docs/dev/TechnicalDebt.md.
2026-10-08 20:05:24 +02:00
boykopovar 239412351e
Merge pull request #639 from boykopovar/feat/no-ingame-shaders-recomp
perf(agc): baseline shader recompilation on registration
In main, baseline recompilation depends on the resource configuration and runs on the first use of each corresponding variant.

This branch prepares IR, the static interface, baseline SPIR-V, and available ABI variants during shader registration. The compiled artifact is separate from per-draw and per-dispatch data.

Before the first execution with a new resource configuration, the runtime reads descriptors, validates compatibility, prepares the binding plan, specializes existing SPIR-V by substituting constants and removing unused branches and computations, materializes invocation data, and creates the Vulkan pipeline. These results are cached.

Variants that depend on linked graphics stages are prepared when the corresponding ABI is resolved. Unregistered compute shaders undergo baseline preparation on their first dispatch, emit an error log, and cache the result.

Subsequent executions reuse prepared artifacts, specializations, and pipelines while updating invocation data and resources as needed.
2026-10-08 20:45:54 +03:00
Adrià 17350cf5fd
Merge pull request #895 from Kikoarl/feat/s-call-b64
feat(shader): implement S_CALL_B64
2026-10-08 19:24:59 +02:00
boykopovar b2a4813307 refactor(shader): remove resource specialization from artifact key 2026-10-08 17:26:38 +03:00
Gjon Gojcevic ede33d56e2 feat(agc): load and store R10_G11_B11 float images
Format 43 packs R as a 10-bit and G and B as 11-bit unsigned floats, which
Vulkan has no format for. Keep it in an R32_UINT image like the other
packed formats without a host equivalent, and convert texels in the shader
on image loads and stores; sampling it still throws.
2026-10-08 15:04:47 +02:00
Adrià 0596a7a274
Merge pull request #1385 from gjonn/feat/recompiler-lwe-on-samples
feat(recompiler): accept lwe on MIMG samples and gathers
2026-10-08 14:43:27 +02:00
popcoder565 a5717b6613 feat(shader): decode halt, trap return, code end, GWS and ordered count instructions
s_sethalt with SIMM16[0] clear is a no-op; s_sethalt 1, s_sendmsghalt, a reached s_code_end, s_rfe_b64, the ds_gws_* instructions and ds_ordered_count throw with the reason at translation. Linear decoding stops at s_code_end like at s_endpgm, so code padded with s_code_end after a final backward branch decodes. Encodings from LLVM SOPInstructions.td and DSInstructions.td, checked against the gfx10 MC tests; semantics from the RDNA 2 ISA guide.
2026-10-08 11:49:06 +02:00
Gjon Gojcevic b692e320c3 feat(recompiler): accept lwe on MIMG samples and gathers
The LOD warning lwe adds to the texel status is texture-streaming feedback,
which is not reported for the T# MIN_LOD_WARN either. Accept lwe on sample
and gather instructions as it already is on loads and stores; lwe on
image_get_lod still throws.
2026-10-07 21:18:19 -04:00
Sanjaysrinivas 36b17177e0 feat(shader): add LDS conditional exchange 2026-10-07 21:40:42 +02:00
Kikoarl f5619c4dcc feat(shader): implement S_CALL_B64 2026-10-07 15:02:33 +02:00
Adrià 7c0ef3393e
Merge pull request #1063 from Celegans12/feat/agc-sampled-8-sint
feat(agc): implement 8_sint sampled images
2026-10-07 14:14:40 +02:00
Adrià 931109b308
Merge pull request #866 from Celegans12/feat/agc-srgb-load-fallback
feat(agc): implement 8 and 8_8 srgb image loads through unorm views
2026-10-07 13:49:58 +02:00
Celegans12 91852719bf feat(agc): implement 8 and 8_8 srgb image loads through unorm views
NVIDIA 610.62 cannot sample R8G8_SRGB, and lavapipe can sample neither
it nor R8_SRGB, so an 8_8 sRGB T# made an image the device does not
support: creating it crashes the NVIDIA driver and lavapipe loads zeros.

The device's format support is read once. An 8 or 8_8 sRGB texture the
device cannot sample is created and viewed as R8_UNORM or R8G8_UNORM,
and SpirvTarget::srgbDecodeFormats makes the materializer mark the
image, so image loads map every channel through a 256-entry table of
the sRGB EOTF rounded to nearest even at bf16 precision, which is what
RDNA2 (gfx1035) returns; both channels of 8_8 are sRGB, and DST_SEL 0
and 1 map to themselves. Samples and gathers of such an image throw,
and its bindless table entries are unmapped like converted formats.
APS5_SRGB_SHADER_DECODE=1 takes this path on every device. Shader disk
cache entries and keys carry the mark: cache format version 7.
2026-10-07 11:52:08 +02:00
Chad 5582c993e2 feat(shader): implement ds_wrxchg2_rtn_b64 and ds_wrxchg2st64_rtn_b64
DS opcodes 0x6e and 0x6f exchange two qwords at offset0 and offset1
scaled by 8 (st64: 512) and return both old values. Each address is
exchanged with its own 64-bit LDS exchange on the locked 64-bit path.
Equal offsets and a destination past v255 throw, as for the b32 forms;
64-bit GDS throws like the other 64-bit DS atomics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:40:39 +02:00
Adrià 46f2050eb5
Merge pull request #896 from alfalfa-star/feat/image-atomic-64
feat(recompiler): implement 64-bit image atomics
2026-10-07 10:54:09 +02:00
Adrià 219a1cf8d2
Merge pull request #916 from adriadam10/feat/s-bfe-i64
feat(shader): implement s_bfe_i64
2026-10-07 10:36:58 +02:00
alfalfa-star 9df592926b feat(recompiler): implement 64-bit image atomics
image_atomic_* with a two-dword data mask (four for cmpswap) is the
64-bit form of an integer image atomic. The decoder rejected it with
"invalid MIMG data mask". PPSA14632 (Unreal Engine) uses
image_atomic_umax this way in a compute shader during its first frames.

Swap, add, sub, signed and unsigned min/max, and, or, xor and cmpswap
now decode with 64-bit data and translate to new ImageAtomic*64 IR
opcodes. An image updated by them gets its own descriptor binding
range, declared as an R64ui image of 64-bit integers, and the module
uses Int64ImageEXT from SPV_EXT_shader_image_int64. The driver enables
shaderImageInt64Atomics when the device offers it and binds an
R64_UINT view of the 32_32 UINT, SINT or FLOAT surface. Without the
feature, recompiling such a shader throws.

64-bit inc, dec and the float atomics still throw, as does any other
access in the same shader to an image it updates with 64-bit atomics.

The new agc_driver_image_atomics64 test runs every operation on 32_32
UINT, SINT and FLOAT surfaces and checks the returned and stored values
against edge cases across the dword boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:21:32 +02:00
Celegans12 26e153dfa2 feat(agc): implement 8_sint sampled images
GFX10 format 6 (8_SINT) T#s threw "sampled image descriptor uses an
unsupported format": neither the recompiler's format table nor the
driver's texture format table had a row for it. Format 6 now reads as
a SINT image through an R8_SINT view, so image_load sign-extends each
texel (0x80 reads -128) and image-table entries of format 6 decode.
8_SINT storage still throws.
2026-10-07 09:02:20 +02:00
Adrià db3e659870
Merge pull request #805 from Celegans12/feat/agc-image-10-11-11-unorm
feat(agc): implement 10_11_11 unorm images through 32-bit uint views
2026-10-07 09:00:03 +02:00
Kikoarl c8e4a17f89 feat(shader): decode s_setkill as s_endpgm 2026-10-07 08:39:41 +02:00