Commit Graph

141 Commits

Author SHA1 Message Date
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
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
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
Petre 88f7a5e0e4 feat(shader): lower full-width MIMG BY2 and BY4 transfers 2026-10-08 21:10:51 +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
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
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
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à 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à 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
DotDebian 984bc57eca feat(shader): implement ds_wrxchg2_rtn_b32 and ds_wrxchg2st64_rtn_b32
Both swap data0 with the dword at addr + offset0 and data1 with the dword
at addr + offset1, and return the two previous values in vdst and vdst + 1.
The offsets are scaled by 4 bytes, or by 256 bytes for the st64 form.
Each location goes through the existing SharedAtomicSwap32.

An encoding whose two offsets are equal is rejected at decode time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 22:46:27 +02:00
Adrià Franch 42ab8af70e feat(shader): implement s_bfe_i64
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-06 18:21:25 +02:00
Chad e263402296 feat(shader): implement image_msaa_load
Decode MIMG opcode 0x80 on 2D MSAA and 2D MSAA array images with a
single-bit dmask and return four dwords: the selected component of the
fragment named in the address and the three that follow it. Each fragment
is read with its own image fetch, adding the fragment step to the packed
address dword so a16 layouts keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:56:34 -05:00
Kikoarl e2974fc4db feat(shader): implement S_SCRATCH_LOAD_DWORD, S_SCRATCH_LOAD_DWORDX2 and S_SCRATCH_LOAD_DWORDX4 2026-10-06 00:12:39 +02:00
Nahuel Genchi a93faff19f feat(shader): implement global_atomic_csub
GLOBAL opcode 0x34 subtracts the data register from a global dword and
clamps the result to zero, returning the previous value. It only exists
in the global segment, so the flat form throws in the decoder, and the
form without glc throws like buffer_atomic_csub does. The clamped
subtract is now a shared helper used by both opcodes.
2026-10-05 10:32:48 -03:00
Adrià Franch d044384a89 feat(shader): implement global_store_dword_addtid
Decode FLAT opcode 0x17 in the global segment and store the data VGPR of
each active lane at the SGPR pair base plus the signed offset plus four
times the lane id, sharing the address path of global_load_dword_addtid.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 08:41:19 +02:00
Dean 3655c2ae34
Merge pull request #506 from adriadam10/feat/global-atomics-float
feat(shader): implement the float and 64-bit inc/dec flat and global atomics
2026-10-05 18:15:22 +13:00
Dean 12cf58256f
Merge pull request #491 from adriadam10/feat/global-atomics
feat(shader): implement the integer flat and global atomics
2026-10-05 18:13:59 +13:00
Dean bdd10f1929
Merge pull request #475 from adriadam10/feat/mimg-coarse-g16
feat(shader): implement image_sample_cd/_g16 variants and fix a16 gradient layout
2026-10-05 18:10:20 +13:00
Dean 4ca60c434c
Merge pull request #524 from DotDebian/feat/mimg-bvh64-intersect-ray
feat(shader): implement image_bvh64_intersect_ray
2026-10-05 18:08:57 +13:00
Adrià Franch c67634a15c feat(shader): implement the float and 64-bit inc/dec flat and global atomics
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 05:05:10 +02:00
Adrià Franch 038ded6382 feat(shader): implement the integer flat and global atomics
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 05:05:03 +02:00
Dean 6d23390ac7
Merge pull request #513 from adriadam10/feat/dpp8
feat(shader): decode DPP8 on VOP1 and VOP2
2026-10-05 15:49:47 +13:00
Dean adac06b59b
Merge pull request #474 from adriadam10/feat/div-f64
feat(shader): implement v_div_scale_f64, v_div_fmas_f64 and v_div_fixup_f64
2026-10-05 15:49:04 +13:00
Dean bd06241645
Merge pull request #447 from adriadam10/feat/vop3-f64-rest
feat(shader): implement v_rcp/rsq/sqrt_f64 and v_trig_preop_f64
2026-10-05 15:48:23 +13:00
Adrià Franch 6138494928 feat(shader): implement image_sample_cd/_g16 variants and fix a16 gradient layout
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 03:39:58 +02:00
Adrià Franch 063437cdcd feat(shader): implement v_div_scale_f64, v_div_fmas_f64 and v_div_fixup_f64
These make up the precise f64 division macro compilers emit for a / b.
Like the f32 ops, the rules were measured on an RDNA2 GPU (41152 rows,
model matches all of them):
- div_scale decides from the exponent fields only: 2^128 or 2^-128
  scaling and VCC for differences >= 768 or <= -768, a denormal or huge
  (>= 2045) denominator and a numerator exponent <= 53; a NaN source is
  passed through unchanged and a zero input gives 0xfff8000000000000.
- div_fmas scales by 2^128 when the exponent of S2 is >= 1024, else
  2^-128, before the single rounding, so it reuses the exact fma
  emulation with the scale folded into its final rescale.
- div_fixup follows the ISA: NaN sources are quieted, a NaN quotient
  with finite inputs becomes +-inf, exponent differences below -1075
  give a signed zero.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 03:37:13 +02:00
Adrià Franch 4f901b9a77 feat(shader): implement v_rcp/rsq/sqrt_f64 and v_trig_preop_f64
Decode and translate the remaining unary f64 transcendentals and
v_trig_preop_f64.

On RDNA2 hardware v_rcp_f64, v_rsq_f64 and v_sqrt_f64 are approximations
(relative error up to ~2^-24.3 over 8209 inputs; sqrt(1.0) is not even
exact), so they are emitted as exact double operations and the test
compares against the hardware value with a 2^-23 tolerance. Special
cases are exact and selected on bits: NaN inputs are quieted (RADV keeps
signaling NaN on FDiv), negative inputs give the default NaN
0xfff8000000000000, rsq(-0) = -inf, sqrt(-0) = -0.

v_trig_preop_f64 matches the hardware bit for bit on 24627 results plus
a sweep of the table tail: the 2/PI table is 1184 bits (bits below b17
read as zero), shift = 53 * S1[4:0] + max(exp - 1077, 0), +128 scale for
exp >= 1968, omod ignored. The 53-bit window is read from a private u32
table and scaled in two exact steps so only the final multiply rounds.

Stacked on the f64 infrastructure of #446.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 03:36:14 +02:00
Adrià Franch 69e2d801d1 feat(shader): decode the s_endpgm variants, s_round_mode and SMEM probe/discard
s_endpgm_saved and s_endpgm_ordered_ps_done end the wave like s_endpgm
(checked on an RDNA2 GPU: nothing after them runs), so they decode to
SEndpgm and the control flow graph treats them as terminators.
s_atc_probe, s_atc_probe_buffer and s_dcache_discard(_x2) have no visible
effect and translate to no-ops like the other scalar cache controls.
s_round_mode is ignored like s_setreg MODE writes; listed in TechnicalDebt.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 03:34:37 +02:00
Adrià Franch 391eb6ffe8 feat(shader): decode DPP8 on VOP1 and VOP2
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 03:32:30 +02:00
Dean 70596d78eb
Merge pull request #577 from CnRJay/feat/s-getreg-mode
feat(shader): implement s_getreg_b32 for the MODE round mode fields
2026-10-05 14:29:24 +13:00
Dean 13e0afcc00
Merge pull request #576 from CnRJay/feat/vop-legacy-fma-dot2
feat(shader): implement v_dot2_f32_f16
2026-10-05 14:27:40 +13:00
Dean 359aa37233
Merge pull request #594 from DotDebian/feat/shader-buffer-atomic-csub
feat(shader): implement buffer_atomic_csub
2026-10-05 14:25:56 +13:00
DotDebian bf635fae68
feat(shader): implement image_bvh64_intersect_ray
MIMG 0xe7 is the node test of image_bvh_intersect_ray with a 64-bit node
pointer: the pointer takes the first two address dwords (low, high), so
the instruction addresses 12 dwords, or 9 with A16.

The node index and address are computed from the whole pointer. A zero
base in the T# is a null BVH only for the 32-bit form: with 64-bit
pointers the T# may cover all of memory from base 0 and the pointer then
carries the node address, so only the T# size bounds the node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:26:32 +00:00
DotDebian da9752bd5f feat(shader): implement buffer_atomic_csub
MUBUF opcode 0x34 subtracts the data register from a buffer dword and
clamps the result to zero, returning the previous value. The form without
glc throws: no GFX10 target is known to provide it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 02:15:47 +02:00
Chad d78eea1f5f feat(shader): implement the 64-bit LDS atomics
ds_add/sub/rsub/inc/dec_u64, ds_min/max_i64/u64, ds_and/or/xor/mskor_b64,
ds_cmpst_b64/f64, ds_min/max_f64, their _rtn forms and ds_wrxchg_rtn_b64
threw in the decoder.

LDS is a 32-bit workgroup array, so the two dwords are read and written
under a lock dword placed after the guest LDS, which is cleared with a
workgroup barrier at entry. The lock is acquired and released in the same
loop iteration, so lanes of one subgroup cannot deadlock on it. Stages
whose LDS is a function variable update it directly. 64-bit GDS atomics
throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 18:14:24 -05:00
Chad 4e888083f9 feat(shader): implement s_getreg_b32 for the MODE round mode fields
SOPK 0x12 threw in the decoder. The recompiler emits round to nearest
even, which s_setreg_imm32_b32 already requires, so reads that stay
within MODE bits 0..3 return 0. Other hardware registers and fields
throw with the register and bits read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 18:11:59 -05:00
Chad abbcb31e54 feat(shader): implement v_dot2_f32_f16
VOP3P 0x13 threw "VOP3P opcode is not implemented". It computes
src0.lo * src1.lo + src0.hi * src1.hi + src2 like v_dot2c_f32_f16, with
the VOP3P op_sel/op_sel_hi and neg_lo/neg_hi modifiers on the packed f16
sources, neg on the f32 accumulator and clamp. op_sel and neg_hi on the
accumulator throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 18:09:01 -05:00
Dean 3fe90689ca
Merge pull request #562 from adriadam10/feat/image-atomics-float
feat(shader): implement image_atomic_fmin, fmax and fcmpswap
2026-10-05 11:44:47 +13:00
Dean b44b308c53
Merge pull request #333 from adriadam10/feat/sopk-misc
feat(shader): implement s_cmovk_i32, s_version and s_setreg_imm32_b32
2026-10-05 11:41:47 +13:00