fix(vk): AMD/Intel shader translation fixes (out-of-bounds fetches, gathers, NaN tests) #2457
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2457
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/vendor-translation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
On AMD, the ground fog draws a pale stepped box at the left, right and top edges of the screen. AMD's older Windows compiler can let NaN tests fail, which shows as black and white blocks. And gathers on AMD and Intel can pick different texels from the console's at texel edges. This PR changes the shader translation to work around these, only on the drivers that need it. NVIDIA's driver gets none of it: the game's translated shaders on NVIDIA are byte for byte what they were.
What changed
Which fixes a GPU gets is decided once, from its Vulkan properties, in
gpu/vk/vk_vendor.h. The log prints the result as onevk: vendor fixesline. Each fix has anRX_VK_switch that forces it on or off on any GPU (listed in docs/development.md).EmitImageFetch). The fetch itself reads in-range coordinates, level and sample, so it never leaves the image. Texel buffers are checked only when robustBufferAccess2 is off: Robust buffers set to Off,RX_VK_ROBUST=0, or a driver without it. When it is on (the default), it already returns zero for their out-of-bounds reads. Whether they are checked is part of the program cache's stamp.RX_VK_FETCH_BOUNDS=0/1RX_VK_GATHER_OFFSET=0/1OpIsNan. This coversFPIsNan16/32/64, the colour outputs' NaN guard and the f32→f16 conversion.RX_VK_NAN_BITS=0/1.x, and a shader would have to read the alpha of an out-of-bounds fetch from a one-to-three-channel texture to see the difference.robustImageAccess2. robustImageAccess2 (off in Hookshot since its first release) would match NVIDIA exactly, including alpha 1 for formats without alpha, and needs no re-translation. But it is device-wide: it bounds-checks every image load, store and fetch in every shader on the device. Its cost is unmeasured on the AMD and Intel cards that would get it, and none of us can measure it here. The shader check is limited to the 520 programs that fetch from images. The trade-off is the alpha difference above. If the lab or players find that the alpha matters, or that the shader check costs more than expected, robustImageAccess2 for non-NVIDIA devices is a small follow-up.gpu/vk/vk_vendor.h, thevk: vendor fixesblock in vk_main.cpp, its switches row in docs/development.md andtests/test_vendor_fixes.py. Each carries only its own fixes, so either can merge first. Whichever merges second gets a trivial conflict in those four files. The resolution: keep both sets ofVendorFixesfields, theirvendor_fixes()lines andRX_VK_overrides; merge the twologfcalls into onevk: vendor fixesline with all five values; join the two docs rows; and in the test, concatenate the FIELDS lists, each device's digit strings (Intel's two first) and the switch names, combine the twocheck_sourcebodies, and keep #2456'sstatic_a2cinversion in the expected-value line (RX_VK_DYN_A2C=1turns that fix off). This PR's copy of the test dropped that branch because it has no such field.GENERAL, so it doesn't pay the decompress cost that change removes.Credit
texelFetchof depth in the ground-fog shader, found by the author of Ocarina of Lain on an RX 9070. This is the idea only, reimplemented here in the translator; no code was copied.runtime/vk_caps.c(Valiantsin Dzerakh, MIT).Verified on NVIDIA (RTX 3090, Linux, driver 620.70.06)
tests/test_vendor_fixes.pygives 16 sets of device properties to the realvendor_fixes(): NVIDIA on Windows and Linux, NVK, AMD's Windows driver in both branches and with no driverInfo, RADV on a desktop card and a Steam Deck, AMDVLK, Intel Windows on integrated and Arc, ANV, and llvmpipe.tests/test_vendor_translation.pybuilds a Sirit compute shader with the realFetchInBoundsandIsNan. It fetches from every texture type a fetch can read (texel buffer, 1D, 1D array, 2D, 2D rect, 2D array, 3D, 2D multisampled) and tests f16/f32/f64 NaNs. It gathers too, as above.EmitImageFetchis checked to be the old code, word for word.OpIsNanis left. The texel buffer's fetch is checked only in a third module made as if robustBufferAccess2 were off.OpIsNanfor quiet, signalling and negative NaNs, ±infinity, denormals, FLT_MAX, ±0 and a value that overflows f16.RX_VK_FETCH_BOUNDS=1). It changes 520 of the 46,676 programs (2,533 of 53,412 variants). All 2,518 changed SPIR-V modules pass spirv-val, with the device's uniform-buffer standard layout and scalar block layout.RX_VK_FETCH_BOUNDS=1 RX_VK_GATHER_OFFSET=1 RX_VK_NAN_BITS=1, this branch after the review fixes). All 38,809 programs translate, the same counts as without the fixes. Every unique SPIR-V module was run through spirv-val with the device's layout rules: 50,808 modules, 2 invalid. Those two (programs743906830fa2e5d1and3aa6798b83cf18a2, a dominance error in the control flow) are just as invalid in main's own translation without the fixes, so they come from elsewhere in the translator. None of the three fixes adds blocks.tests/run_all.pypasses, apart from checks that fail on this PC without the change too (nozstandardortkinterhere).Not tested: please help if you have an AMD or Intel GPU
I have no AMD or Intel GPU, so none of the fixes has been seen working on the hardware it is for. The NaN and gather fixes were not run with the full game here; only the fixture tests above cover them. Reports with
hookshot_log.txtare very welcome, especially from:RX_VK_FETCH_BOUNDS=0.RX_VK_GATHER_OFFSET=0.RX_VK_NAN_BITS=0.Also not measured: the GPU cost of the bounds checks on AMD and Intel. The checks are a few instructions per texel fetch, in 520 of the game's programs.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00