The resource materializer refused every atomic image descriptor whose
format was not 32_UINT. RDNA2 image atomics act on the raw dword and
the numeric format only affects addressing, so 32_SINT and 32_FLOAT
surfaces are now accepted with the Uint numeric class and run through
the existing integer atomics and float compare-exchange loops. Other
formats still throw, and the message now names the format.
DescriptorBinding gains imageAtomic, carried through the shader disk
cache (format version 4) and the resource content key. The driver
binds those elements through a cached R32_UINT view of R32_SINT and
R32_SFLOAT storage images.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
image_sample_*_o takes its texel offset from an address VGPR. The emitter
accepted only an immediate there and failed with "requires a constant texel
offset for image sampling" for any other, including an offset the program
moves into the VGPR under EXEC.
An offset that resolves to a constant at its packed address position stays a
ConstOffset. Any other becomes the Offset image operand, which Vulkan allows
on sampling instructions only with VK_KHR_maintenance8's maintenance8 feature
and the ImageGatherExtended capability. The device enables maintenance8 when
available and reports it through SpirvTarget::nonConstantImageOffsets, which
the cache key, the request serialization (version 6) and the SPIRV-Tools
validator options follow. Without it the sample still fails.
agc_shader_replay --maintenance8 recompiles a request for such a device.
Every run recompiled every shader: the recompiler's variant cache and
the device's VkPipelineCache only lived in memory, and the first frames
of a title spent hundreds of milliseconds per large program in the
front end, the emitter and the optimizer.
Compiled variants (the SPIR-V plus the compiled shader info and binding
allocation that per-snapshot binding population needs) are now stored
on disk, one file per key, written atomically by a background thread,
and a later run loads them instead of compiling. The key holds every
input the in-memory variant cache matches on: the in-memory recompile
key (stage, code hash, stage registers, user data count, target), every
code word, the host subgroup size, the binding layout, the resource
specialization, and the values of the APS5_* switches the recompiler
sources read (found at build time; switches that only report are left
out). Entries live under a directory per source version, a build-time
hash of the recompiler and AGC driver sources and the build
configuration, and carry their key and checksums: an entry whose
format, version, key, size or checksum does not match, or whose payload
does not decode exactly, is ignored and recompiled. Directories no
build used for two weeks and stale temporary files are removed. Requests
under the debug probe bypass the disk cache.
The device's VkPipelineCache is loaded at creation when the file's
checksum and Vulkan header match the device (vendor, device and
pipelineCacheUUID; the driver version is in the file name), saved every
10 s while it grew, and saved at teardown.
Location: a shader_cache folder beside the running executable (not the
working directory), so the relinked game stays a self-contained folder;
ANYPS5_SHADER_CACHE_DIR overrides it. ANYPS5_NO_SHADER_CACHE=1 turns both caches off; the AGC
tests run with it set so they never write to the user's cache.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ