Commit Graph

25 Commits

Author SHA1 Message Date
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
boykopovar eb68ad3b02 fix(shader): preserve main buffer alignment and image formats in prepared shaders 2026-10-08 17:51:05 +03:00
boykopovar 2d93308780 fix(shader): preserve main behavior in cached specialization 2026-10-08 17:37:25 +03:00
boykopovar 7431e5a6e1 perf(shader): restore prepared vertex inputs + harden buffer specialization 2026-10-08 17:28:55 +03:00
boykopovar 73816838dc perf(shader): add pipeline specialization and direct buffer access (wip) 2026-10-08 17:28:34 +03:00
boykopovar 1174069239 feat(shader): select image and sampler resources at runtime 2026-10-08 17:26:34 +03:00
boykopovar b08c410b97 feat(shader): move buffer accesses to runtime descriptors via bda 2026-10-08 17:25:14 +03:00
Adrià 8f510f31ab
Merge pull request #1066 from Celegans12/feat/shader-buffer-limit
feat(shader): accept more than 32 buffers per shader up to the device limit
2026-10-07 14:20:34 +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 1c5ed6594d feat(shader): accept more than 32 buffers per shader up to the device limit
The resource tracker refused a program's 33rd distinct V# with "buffer
resource limit exceeded". The 32 was a recompiler constant, not a
Vulkan limit: every buffer is one constant-indexed element of the guest
buffers binding, which ShaderResources checks against the device's
storage-buffer limits.

Drop ShaderInfo::MaxBuffers and the tracker's refusal, and size the
SPIR-V emitter's per-buffer offset list from the binding layout. When
the user data and offsets do not fit in the push constants, they all go
to the shader data buffer as before. ShaderResources counted only
storage buffers against maxPerStageResources (200 on Intel UHD) and now
adds the stage's sampled and storage images.

agc_driver_many_buffers reads and writes 52 and 124 buffers, and
agc_driver_graphics rejects buffers plus an image above the limit.
2026-10-07 09:17:47 +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
DotDebian be866e4214 feat(shader): store through flat and global addresses
flat_store_* and global_store_* decoded and translated, but a store whose
segment is not scratch was refused when the SPIR-V was emitted ("writable
FLAT/GLOBAL addresses require GPU ownership tracking").

Such a store now goes through the BDA page table like a store through a
GPU-selected V#: the write lookup needs Write permission, which only a
writable registered range imported in place has, and the written page is
noted for the host to mark GPU-written. Byte and short stores, and dword
stores to an address that is not dword aligned, are stored byte by byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 05:05:03 +02:00
Adrià Franch e2ac1a6690 feat(shader): implement image_load_pck and image_load_mip_pck with signed variants
Return the raw texel bits: dmask bit i selects texel dword i, dwords past the
texel read 0 and the _sgn forms sign-extend texels narrower than 32 bits
(measured on RDNA2 hardware). Only formats whose bits are exactly recoverable
from the sampled view are accepted (unsigned/signed integer, unorm up to 16
bits, 32-bit float components), on a direct sampled image with identity
swizzle; anything else throws.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-04 22:32:13 +02:00
Dean Galvin ad72175a67 fix(recompiler): split image reads whose T# or S# is a Phi of SRT reads
A sampler (or texture) chosen by scalar control flow reaches the image
operation as a Phi of two ReadConst values. The SRT walker only accepts
invariant Phis, so GetHandle threw "GetSamplerResource dword 0 is not a
valid runtime value" and the draw was skipped (G-buffer and HDR draws
in PPSA21564).

Before tracking, a read-only image operation (sample, gather, LOD query,
size query, load) whose descriptor dwords are Phis of one block is
copied once per distinct incoming descriptor. Each copy gets its own
memory entry and descriptor handles whose dwords are the edge's values,
recomputed before the operation (SRT reads, user data, the shader base
and pure uniform arithmetic over them only). The results are selected
by a Bool Phi of the edge that entered the Phi block. The copies run
where the original did, so implicit derivatives are unchanged, and the
host binds every edge's descriptor. Any other shape (a nested Phi, a
dynamic read on an edge, a store or atomic) is left alone and still
throws.
2026-10-03 10:02:51 +13:00
STL1te 6b36c050fe style: drop the branch's code comments per CONVENTIONS.md
Only the lines this branch added lose their comments; the commits before
keep them, with the reasoning behind each change, for whoever digs into
that code later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:25:29 +03:00
STL1te 9bb94163ea feat(shader): image_bvh_intersect_ray tests the ray against the BVH node
Every ray query returned a miss (a stub). The node test is now the GFX10
(RT IP 1.1) one AMD's GPURT software fallback defines (IntersectCommon.hlsl)
with the TriangleNode1_0 and BoxNode1_0 layouts, as SharpEmu ports it: the T#
(base, size, box grow and sort, triangle return mode) and the node pointer
are run-time values, triangle nodes return t over its denominator with the
barycentric numerators or the triangle id, float16/float32 box nodes the hit
children (clipped slabs, NaN misses, optionally sorted by entry time); an
inactive lane, a null BVH, an out-of-range node or another type returns four
invalid dwords.

The decoder addresses 11 dwords (8 with A16, the directions as halves), the
translation emits ImageBvhIntersectRay with the T#, MakeImageAddress and exec,
and the program takes the BDA path: one probe covers the node and direct loads
read it (a node the table does not map as one range records an Unmapped
fault); EmitBdaDwordReads can read every dword for the per-byte fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:22:22 +03:00
STL1te 74454ee9ca feat(shader): scalar buffer loads through a GPU-selected V#
A traversal builds the V# of a bottom-level structure from a pointer it loads
from an instance record, and reads it with s_buffer_load: no binding holds
such a V#, and TakeGpuDescriptor took vector raw dword loads and stores only,
so the resource analysis failed on the SGPR chain.

A ReadConstBuffer through a V# the SRT walker cannot compute is a
MemoryInfo::gpuDescriptor access too: the dword at the V#'s base plus the
dword-aligned offset, read through the BDA page table, zero past
STRIDE * NUM_RECORDS bytes (NUM_RECORDS for stride 0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:22:21 +03:00
STL1te 21cb5676c7 feat(shader): buffer access through V#s computed on the GPU
A V# the SRT walker cannot compute (loaded from a descriptor heap at a
GPU offset, or built by the program) has no binding to hold it. Raw
dword loads and stores of 1-4 dwords through one now decode the V# in the
shader, apply the RDNA2 bounds rules (OOB_SELECT, stride, swizzle,
ADD_TID, format 0) and go through the BDA page table, as Kyty does.

Stores need Write permission, which only ranges that are a writable
allocation's host import get, so a store into a mirror or a copy faults
rather than being lost. The shader notes each written page in an
open-addressed set behind the fault record; once the work completed the
host marks those pages GPU-written, and an overflowing set throws.
Formatted, typed, sub-dword and atomic access through such a V#, and
their use outside compute shaders, still fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:22:18 +03:00
devilismyfriend 29b4601564 perf(agc): dispatch and draw recipes, data-only cache hits, unit shadows, bindless image tables
Dispatch cache with per-key value variants and data-only hits (flat-SRT leaves the recompiler
proves pure are refreshed into the resource template instead of re-captured), dispatch and draw
recipes replaying a proven prepare, register-keyed draw entries, template data refresh, unit
shadows in device-local slabs, 64 KiB block-unit storage tracking with windowed detile, DCC
clear-key proofs, per-class GPU timing, a CPU copy path with batch read tracking, present slot
ring, rate-limited reaps and lazy completion counting, plan-failure and poisoned source memos,
bindless image tables (runtime-indexed descriptor arrays from a CPU-read table) so the
per-frame compute program that failed its plan now compiles. Worker affinity opt-in, per-draw
logs behind APS5_TRACE_DRAWS, wait-timeout reports include the recorder's view of the label.
Fixes a use-after-free behind BDA-miss dispatch snapshots and the CPU-write stamp of
UnchangedSinceCollected. Intro-video stage: 154 -> ~500 presents per 10 s at 4K.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
2026-09-26 19:00:40 -07:00
devilismyfriend 87911b3bb5 fix(recompiler): saveexec operand order, atomic-zero rewrite, cache keys
- s_*_saveexec reads its source before writing the old EXEC into the
  destination, so the aliased form (vcc, vcc) computes exec & vcc; the
  per-lane exec bit comes from the lane's own bit. Every Bink 2 decoder
  kernel uses that form; this was the video corruption.
- buffer atomics add/sub/or/xor with a zero operand become an atomic
  load or nothing.
- DescriptorBinding carries bufferWritten/bufferAtomic/imageWritten;
  results expose a variantId and share SPIR-V copy-on-write; source
  keys use a length plus 64-bit hash; captures can be reused.
- wave-LDS ordering barriers, v_movrels/v_movreld lowering, SMEM with a
  VCC base, f16 conversion opcode fix, a per-function SPIRV-Tools pass
  list, env-gated IR dumps and probes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo
2026-09-25 16:27:49 -07:00
boykopovar 760d1f660e fix(shader): resource tracker dword 0: pc instruction in ex 2026-09-18 12:54:47 +03:00
boykopovar 95df53181c fix(shader): buffer resource dword 0 detailed exception in tracker 2026-09-18 12:52:03 +03:00
boykopovar b18bec2150 feat(shader): add resource tracker impl 2026-09-17 17:43:03 +03:00
boykopovar d084eed394 feat(shader): rdna memory op decoder impl 2026-09-15 07:07:50 +03:00
Renamed from core/shader/recompilier/Optimization/src/ResourceTracker.cpp (Browse further)