Commit Graph
289 Commits
Author SHA1 Message Date
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
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
4651980eba perf(agc): cheaper shader-memory captures per draw
The per-draw capture of a shader's memory (the SRT walk and the guest pages it reads) cost about
15 us per draw packet in GTA V Performance mode; it now costs about 6.6.

- The SRT evaluator memoizes per plan value in a thread's reused, stamped array instead of a hash
  table allocated and grown on every walk (evaluate 5.3 -> 3.6 us per capture).
- ExtractPlan also stores the plan's values as 32-byte records with argument ids, and the walk
  evaluates that compact copy: the IR walk spent most of its time in cache misses (3.6 -> 2.7 us).
  The evaluator is a template over the node view, so both walks share every opcode's semantics, memo,
  cycle and failure rules. A plan that cannot be expressed compactly keeps the IR walk.
  APS5_VERIFY_SRT_COMPACT=1 walks both and throws on any difference.
- ShaderMemory's valid/read/recent marks are arrays of 64-bit words scanned with countr_zero instead
  of bitsets tested bit by bit (about 1 us per draw packet).
- Captured pages come from a per-thread pool, are found through a short vector with a last-page
  shortcut, and a page no recorded GPU work writes gets the flush hook a whole-page read would make,
  then has each 64-byte block copied when a word of it is first read (about 0.3 us per packet).
  Pages with pending GPU writes and unmapped pages are read as before.
- APS5_PROFILE_DRAW splits the capture time into SRT evaluation and materialization, and prints the
  [capture] line once per 10 s instead of every 500 captures (it cost about 2 us per capture).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Gjon Gojcevic <[email protected]>
2026-10-15 11:11:24 +02:00
MarcZX100 0e7e149cce fix(shader): limit TYPE=0 null images to reads 2026-10-15 01:59:33 +00:00
MarcZX100 682b07eb03 fix(shader): track captured image descriptor words 2026-10-15 01:53:43 +00:00
fdfawef324 1ffc5f672b feat(agc): emulate per-pixel multisample coverage masks
Decode the four PA_SC_AA_MASK fields at the rasterized sample count. Use the native Vulkan mask when all four pixels agree and apply varying masks in the fragment shader, preserving helpers and combining coverage with alpha-to-coverage and shader mask exports. Add the normalized masks to pipeline, draw and shader keys and the versioned replay request.

Refuse unsupported conservative-raster, centroid and early depth/stencil memory-write cases. Synthetic readbacks cover driver submission, depth/stencil suppression, fragment stores and one-sample and four-sample coverage.
2026-10-15 13:00:34 +13:00
Michon 72518f64fb feat(agc): single-sample sample masks as a per-quad-pixel discard
With one sample, PA_SC_AA_MASK leaves one coverage bit per pixel of the 2x2 quad,
so a draw can cover only some pixels of every quad (GTA V renders a target one
quarter of the pixels at a time this way). The pixel stage info carries that 4-bit
mask; a fragment shader whose mask is not full starts by killing the invocation
unless its gl_FragCoord quad position is covered, and runs without early fragment
tests. The mask is part of the recompile cache key and the serialized request
(version 24). Sample masks of multisampled draws stay refused.
2026-10-15 12:59:39 +13:00
Dean ab9a476840 Merge pull request #5583 from BlizzyInc/fix/sample-through-1d
fix(shader): read explicit-LOD 2D samples through 1D T#s as measured
2026-10-15 12:34:15 +13:00
Yossi Yadgar 84a01a06e7 fix(shader): name the buffer and its V# when a descriptor type is unsupported 2026-10-15 01:21:57 +03:00
Adrià 596a0d70aa Merge pull request #5472 from eljackjoestar-cmd/codex/rgba8-uint-force-degamma
fix(shader): decode forced degamma on biased RGBA8_UINT samples
2026-10-15 00:01:33 +02:00
Dean 8ae436891a Merge pull request #5181 from ThatsLeo/perf/shader-compact-resource-plans
perf(shader): keep only evaluable branch conditions in resource plans
2026-10-15 10:56:57 +13:00
billythemenace2andClaude Opus 5.5 3b96840e68 fix(shader): read cube T#s through DIM 2D image_sample and image_load as face 0
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-14 23:37:33 +02:00
mitul72 e52e140f5c fix(shader): read explicit-LOD 2D samples through 1D T#s as measured
A 2D image_sample_l through a 1D T# now takes the 1D runtime mode, as
image_sample_lz already does, instead of failing the runtime image
interface. Measured on RDNA2 (gfx1036) with tools/hw-oracle against the
same sample with DIM 1D: u inside, on and past the edges, v of 0, 0.5, 1,
-0.25 and 3, LOD -1 to 6 on a 5-level R32_FLOAT texture, point, linear and
linear-mip filtering, wrap, clamp and border addressing, and HEIGHT or
DEPTH 3. All 4725 rows matched: the 1D T# decides the addressing and v is
ignored.

The execution test samples a 5-level 1D T# with distinct mip contents at
LODs -1 to 6, fractional ones included, with u inside, on and past the
edges, under point filtering with wrap and clamp and linear filtering with
linear mips and wrap, clamp and border addressing. Every result must match
the same image_sample_l with DIM 1D bit for bit; point-filtered results
must also be the expected texel of the expected level, and linear-mip
results the blend of the two levels the LOD selects.
2026-10-15 10:33:22 +13:00
eljackjoestar-cmd 76eb60af61 fix(shader): decode forced degamma on biased RGBA8_UINT samples 2026-10-14 23:25:53 +02:00
Adrià 33001cebda Merge pull request #5466 from fdfawef324/codex/stencil-export-emulation
feat(agc): replay proven finite stencil reference exports
2026-10-14 22:49:30 +02:00
Adrià 0a9a32646e Merge pull request #5461 from eljackjoestar-cmd/codex/single-level-volume-bias
fix(shader): sample single-level volumes through biased 2D accesses
2026-10-14 22:49:08 +02:00
Adrià 2077b5383a Merge pull request #5456 from billythemenace2/fix/shader-2d-compare-on-1d-tsharp
fix(shader): compare through 2D image_sample_c on 1D T#s
2026-10-14 22:48:28 +02:00
Adrià fa3b41c54e Merge pull request #5450 from overlordxrz-source/feat/interp-reference-message
fix(recompiler): name the attribute of an out-of-range interpolation reference
2026-10-14 22:47:49 +02:00
fdfawef324andCodex 97a0a4d098 refactor(agc): separate stencil replay from its follow-up topics
Move bounded vertex folding and empty-image feedback into separate topics. Keep the replay coverage proof, stage contracts, finite-reference tests and mapped cache regressions; version the stencil layout separately as format 34.

Co-Authored-By: Codex <[email protected]>
2026-10-14 22:08:48 +02:00
fdfawef324andCodex 90be83b71a fix(agc): fold bounded vertex lane masks before stencil replay
Preserve replay refusal for observable lane-dependent values, non-vertex stages, unknown subgroup widths and varying-size modules. Validate the actual native vertex subgroup contract and retain compiled single-lane targets.

Co-Authored-By: Codex <[email protected]>
2026-10-14 22:08:36 +02:00
fdfawef324andCodex 77521f7ad2 feat(agc): replay proven finite stencil reference exports
Preserve instance and triangle order with one dynamic-reference shader pipeline. Require bounded references, complete export coverage, replay-safe mask control and resources; refuse unsupported side effects and feedback.

Co-Authored-By: Codex <[email protected]>
2026-10-14 22:08:35 +02:00
Adrià FranchandClaude c0e31dd7bc fix(shader): use the image table marker for the single-level volume bias mode
Co-Authored-By: Claude <[email protected]>
2026-10-14 21:59:09 +02:00
eljackjoestar-cmd 89777fcaa1 fix(shader): sample single-level volumes through biased 2D accesses 2026-10-14 21:58:18 +02:00
billythemenace2andClaude Opus 5.5 0851c08b60 fix(shader): compare through 2D image_sample_c on 1D T#s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-14 21:54:00 +02:00
MarcZX100 825a26751c fix(shader): accept TYPE=0 images on current main 2026-10-14 19:53:00 +00:00
ThatsLeo cc4d3edb28 fix(shader): judge an extract by its source in MayEvaluate
EvaluateExtract evaluates only through its source, so an extract of a
non-invariant counter made a loop's latch condition look evaluable.
2026-10-15 08:22:09 +13:00
ThatsLeo 26f0331094 perf(shader): keep only evaluable branch conditions in resource plans
A plan copied every control-flow condition with all its operands, though one
that depends on a vector register is never evaluated. Such conditions are
dropped, and the copied values live in one arena without use lists.
2026-10-15 08:22:09 +13:00
Adrià 276608d2cf Merge pull request #4475 from Pipodi/feat/image-table-indirect-columns-v2
feat(agc): image-table records that hold a pointer to the T# or split it over two loads
2026-10-14 19:46:11 +02:00
Adrià 8ba869d303 Merge pull request #4450 from Pipodi/feat/tessellation-instanced-hull
fix(shader): number an instanced draw's hull patches across its instances
2026-10-14 19:44:52 +02:00
Dean 8b8bfe0b6e Merge pull request #4820 from nicolasabosch/feat/agc-sample-msaa-color
feat(agc): sample a multisampled color target through its 2D MSAA texture
2026-10-15 06:42:29 +13:00
billythemenace2andClaude Opus 5.5 bd09862e55 fix(shader): read 1D T#s through 3D image_sample and image_load accesses
A 3D image access bound to a 1D T# matched no runtime image mode and threw
"image descriptor is incompatible with the static runtime image interface"
(SONIC SUPERSTARS, PPSA06888, which reads a 1x1 1D T# as 3D with a plain
image_sample and an image_load). Add a 1D mode for 3D accesses whose only
uses are image_sample_lz, plain image_sample or mip-less image_load.

Measured on RDNA1 (RX 5700 XT, gfx1010) with the hardware oracle:
image_sample_lz reads the texel u selects and ignores v and r with every
addressing mode; a plain image_sample takes its texel and LOD from u alone;
image_load reads the x texel for any y when z is 0 and returns zero for any
other z, as the 3D-on-2D load measured in #2023 does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QQNVXyqeecpyneonkYL6H1
2026-10-14 18:32:22 +01:00
Alex ColliniandClaude Opus 5.5 30e85a3a2e fix(shader): number an instanced draw's hull patches across its instances
With GE_CNTL.BREAK_WAVE_AT_EOI clear, the instances of a tessellated draw share
hull threadgroups: the relative patch index counts on through the instances,
while the host's PrimitiveID restarts with each one. The local stage now passes
its draw-relative instance (InstanceIndex - BaseInstance) to the hull, which
numbers its patches instance * patches-per-instance + PrimitiveID before taking
(mod PRIM_GRP_SIZE) mod NUM_PATCHES. Instances that start a threadgroup anyway
(BREAK_WAVE_AT_EOI, or patches per instance a multiple of the group) keep the
per-instance PrimitiveID.

This replaces #4201's refusal of a hull or domain that uses its relative index
as data while BREAK_WAVE_AT_EOI is clear, and builds on its decode of the bit
(breakAtInstance, request serialization and draw keys).

- Hull and domain cache keys hold the patches per instance instead of the bit;
  an indirect draw recompiles its hull and domain for each record's instance
  count.
- The device enables shaderDrawParameters when available. Without it, a hull
  using its relative index as data in such a draw is refused, as is a domain
  doing so (passing the instance on to the domain is not implemented).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 19:08:18 +02:00
Alex ColliniandClaude Opus 5.5 55eefe9c5e feat(agc): plan table columns whose descriptor spans two loads of a record
A descriptor whose dwords come from two scalar buffer loads of the same
record, where one load's offset carries an immediate addend, was refused
because the column wanted one offset expression and one buffer node for
every dword. The column now peels an immediate addend off each read's
offset and compares effective offsets (memory offset plus addend) and
the remaining base expressions, and accepts distinct buffer nodes that
are equivalent. Dword 0 keeps its offset expression, so columns that were
already planned are planned the same way.

Folding a second load into the first changes where its offset wraps:
at a dynamic offset of 0xfffffff0, a second load at +16 wraps to the
start of the buffer, while the folded read lands past 4 GiB. A column
folds a load only when its addend is no smaller than dword 0's and its
immediate is small, and it records dword 0's addend and the largest extra
addend. A record whose offset would carry past 32 bits between the two
loads is not read and becomes OffsetCarry poison.

PPSA26344 pixel shader 0x8000296000 reads T# dwords 0-3 with an
s_buffer_load_dwordx16 at key * 0x88 and dwords 4-7 with an
s_buffer_load_dwordx4 at 48 + key * 0x88.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 18:20:24 +02:00
Alex ColliniandClaude Opus 5.5 c794273ab2 feat(agc): implement image tables whose records hold a pointer to the T#
A table column can now read its descriptor through a 64-bit pointer
stored in each record: the shader loads the record's pointer at
key * stride + addend + offset from a scalar buffer, then the T# (or S#)
through that pointer. The materializer reads each record's pointer when
it builds the table, reads the descriptor behind it and records one
read range per record. Pointer columns take their own path ahead of the
batched record reader, since a descriptor's address is known only once
its record's pointer is read. The column is planned only when the descriptor
dwords are read at an immediate offset from a GetAddressResource whose
two dwords are consecutive reads of one buffer at the same affine offset.

PPSA26344 compute shader 0x8000333c00 picks a record per lane in a
waterfall loop, reads the record's pointer from it and samples the
image behind it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 18:20:24 +02:00
Celegans12 34525fdf7a feat(agc): implement image tables loaded through 64-bit pointers
Plan runtime-indexed T# and S# columns read through a 64-bit pointer.
Preserve the console offset alignment, signed immediate and key bounds.
Track the descriptor dwords consumed by each table in its invocation.
Reject table reads when a writable buffer or storage image overlaps them.
Cover the overlapping-storage fault and isolated second-table behavior.
2026-10-14 16:43:57 +02:00
Celegans12 d9e47d1e98 feat(agc): implement image and sampler tables indexed at runtime offsets
Materialize runtime-indexed image and sampler records into descriptor
tables while keeping descriptor selection in the shader. Report invalid
active entries through the existing deferred fault buffer.

Bind fragment tables in the fragment set when pipeline libraries split it,
and reserve a physical descriptor for empty tables. Reject unsupported
sampler, border, cube and anisotropic pairings per entry. Keep one column
per heap access shape, one T# shared by several image operations included
(milescoviello's #5550 case), and narrow it to the union of its keys'
domains when every key has one (SleglJan's key-domain changes). Plan
columns read at (key << n) & mask over their whole domain (tibzejoker's
fix). Read records in runs through SleglJan's bulk reader, and reject
entries whose surface has no mapped byte, as Tamalero proposed. Store
table columns in disk plans; update the runtime ABI and disk format. Bound
table-sized entries in the resource cache (65,536 table elements) and the
dispatch cache (256 MiB of captured words), evicting LRU.
2026-10-14 16:43:57 +02:00
MarcZX100 1749c98025 fix(shader): accept TYPE=0 images during materialization
(cherry picked from commit 52992026a489b809aacaa47ff490bae57f227139)
2026-10-14 14:39:44 +00:00
Adrià FranchandClaude 353094a254 Revert "Merge pull request #5089 from fdfawef324/feat/recompiler-waterfall-descriptors"
agc_driver_waterfall_images fails on main since fd438f663: its compute shader
runs an LOD query with a local size of 8x1, and the module gets
DerivativeGroupQuadsKHR, which SPIR-V validation rejects unless both
dimensions are even (VUID-StandaloneSpirv-DerivativeGroupQuadsKHR-10151).

This reverts commit fd438f663, reversing changes made to 51031742e.

Co-Authored-By: Claude <[email protected]>
2026-10-14 14:38:28 +02:00
Adrià fd438f663d Merge pull request #5089 from fdfawef324/feat/recompiler-waterfall-descriptors
feat(recompiler): plan waterfall loops over per-lane T#s as non-uniform tables
2026-10-14 14:01:42 +02:00
Adrià c7844d9cb5 Merge pull request #4948 from fdfawef324/perf/recompiler-giant-compute
feat(recompiler): reuse pure IR values recomputed in dominated blocks
2026-10-14 13:59:06 +02:00
fdfawef324andClaude Opus 5.5 bdb0a3f59f fix(recompiler): bind no record of empty per-lane tables and compare bound modes only
A per-lane table V# with num_records 0, a null V# included, threw at dispatch
on its stride (0 is less than the record offset plus 32) although no lane can
hold a record, also when no lane enters the waterfall. With no records every
OOB_SELECT puts each load out of range (the GFX10 table in Mesa's
ac_descriptors.c), so such a table now binds no record and every lane that
runs the access reads zeros; the swizzle, ADD_TID, OOB_SELECT and stride
checks apply only to a V# with records.

The implicit-derivative mode check compared every bound record with record 0,
whose mode is 0 when it is null, so a table with a null record 0 and bound
records of one other mode was refused. Only bound records are compared now.
Lanes whose record is null or outside the table take the zero path under
record 0's mode, so their quad neighbours' derivatives can still be undefined;
the debt entry records this and the 16-record limit of the whole table.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 13:24:53 +02:00
fdfawef324andClaude Opus 5.5 8bca46fb06 fix(recompiler): refuse per-lane waterfall tables over masked T#s or mixed modes
A lane whose IDXEN load was skipped keeps the T# VGPRs it had before, and a
waterfall that reaches it uses that value as its T#. The fold refused only a
value that was itself a uniform descriptor or a table read, so a default T#
copied into the VGPRs under EXEC, or merged by a phi, was accepted and those
lanes read zeros. The skipped lanes' values are now followed through the masked
selects and phis that all eight dwords share, and the fold is refused when an
arm is a descriptor or a table read.

Every lane of a per-lane table runs the access with its own record, and the
runtime image mode picks the SPIR-V path per lane, so lanes of one quad whose
records need different modes take different paths around an implicit-derivative
sample or LOD query, where derivatives are undefined. Such a table now throws
at dispatch; accesses of one table share the check, so they keep one table.

The test also covers v_readfirstlane and v_cmpx_eq_u64 waterfalls and refuses
loops that compare seven T# dwords, run the image instruction after EXEC is
restored, or store.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 13:24:53 +02:00
fdfawef324andClaude Opus 5.5 f234476b21 feat(recompiler): plan waterfall loops over per-lane T#s as non-uniform tables
A waterfall loop (s_ff1 or v_readfirstlane picks a lane, v_readlane copies
its T# to SGPRs, v_cmpx_eq keeps the lanes whose T# VGPRs match, the image
instruction runs, the matched lanes leave the loop) reads the T# from VGPRs,
which no descriptor source evaluates, so planning failed with "GetImageResource
dword 0 is not a valid runtime value".

When every T# dword of an image read, sample, gather or query comes from
v_readlane_b32 or v_readfirstlane_b32 and the EXEC its results are written
under implies that each of them equals the lane's own VGPR, the access takes
each lane's own T#. A T# that each lane loaded with buffer_load_dword* (IDXEN)
from one evaluable V# becomes a bindless image table keyed by the lane's
index, addressed by the V# stride, and its slot is decorated NonUniform.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 13:24:53 +02:00
Nicolas AboschandClaude Opus 5.5 4b71846fab feat(agc): sample a multisampled color target through its 2D MSAA texture
A shader that loads from a 2D multisampled image whose T# names a color
target rendered on the host is bound to a view of that target's image.
Other multisampled textures keep throwing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 23:59:19 +13:00
Dean 9d81b4f6cb Merge pull request #5555 from MidnightApora/fix/agc-2d-array-volume
fix(agc): accept 2D-array image loads and stores on 3D T#s
2026-10-14 23:57:51 +13:00
Dean b5c593aa2f Merge pull request #5550 from milescoviello/fix/shader-shared-table-image
fix(shader): plan a table T# that several image operations share
2026-10-14 23:56:57 +13:00
Adrià 82f112d20f Merge pull request #4451 from Amoenus/codex/feat-alpha-to-coverage-dither8
feat(agc): emulate default eight-sample dithered alpha coverage
2026-10-14 12:55:07 +02:00
Dean c654b199bd Merge pull request #5049 from eljackjoestar-cmd/codex/scalar-buffer-descriptor-fields
fix(shader): ignore unused descriptor fields for scalar buffer loads
2026-10-14 23:06:33 +13:00
Romans Pokrovskis c8b3a37533 feat(agc): emulate default eight-sample dithered alpha coverage 2026-10-14 12:58:43 +03:00
Dean eecf909539 Merge pull request #5188 from EagleBearerYS/fix/shader-images-from-constant-buffers
fix(shader): capture image descriptors read from constant buffers at uniform offsets
2026-10-14 22:58:01 +13:00