Fixed the Xenoblade 3 AMD cutscene crash + 2 other Ryujinx lineage bugs on Linux, here's the root causes
I mess with switch emulation on my steam deck. A few of the fixes turned out to be real bugs in the shared codebase and not deck specific things, so instead of sitting on them I figured I'd write them up. I checked current Ryubing master before posting and all three are still in there. Not looking for anything, take them, port them, whatever. If a dev wants more detail ask and I'll answer in comments.
**1. Xenoblade Chronicles 3 cutscene crash on AMD (RADV)**
The SPIR-V backend emits textureGatherOffsets using the ConstOffsets image operand even when the offsets are runtime values. ConstOffsets requires compile time constants per the spec, but the codegen wraps whatever it has in a ConstantComposite anyway, so when the offsets aren't constant the result is invalid SPIR-V. Nvidia's compiler happens to swallow it, RADV segfaults. That's the whole reason the crash is "AMD only".
Where: Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs, the gather path that builds the offsets array and ORs in ImageOperandsMask.ConstOffsets (around line 1390 in the current tree).
Fix: detect when any offset isn't a compile time constant and don't use ConstOffsets at all in that case. I lower it to 4 separate gathers using the plain Offset operand (which allows dynamic values) and reassemble the components. The XC3 cutscenes that crashed 100% of the time on my deck play fine now.
**2. Black or frozen videos in games on current Linux distros**
The FFmpeg loader whitelist in Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs accepts avcodec 59-60 only. FFmpeg 7 is avcodec 61 and it's what SteamOS, Arch and Fedora ship now, so the library never loads and every H264 game movie (intros, cutscenes) silently fails. Widening the whitelist to 61 is not enough on its own, avutil 59 changed the AVFrame struct layout, so you also need a version aware struct definition or you'll be reading garbage fields.
While I was in there I also turned on slice threading for the decoder, single threaded H264 was too slow for some movies and stalled at syncpoints (Donkey Kong Tropical Freeze intro freeze is this). But the whitelist + AVFrame layout is the core fix.
**3. The "dots" artifact on ground textures on AMD (and probably other bindless weirdness)**
This one took a RenderDoc session on the deck to nail down. Some games index a bindless descriptor array with a per pixel varying index. The vulkan spec says that access is undefined unless it's decorated NonUniform. There IS a MarkNonUniform helper in the tree already (came in with the non uniform indexing PR) but it only decorates the loaded descriptor value. That's not enough on RADV. The compiler still treats the descriptor load itself as uniform and broadcasts one lane's descriptor across the quad, so neighboring pixels sample the wrong texture out of the array. Shows up as bright speckles on tiled ground textures. Tomodachi Life is where I chased it but it'll hit anything doing non uniform bindless indexing.
How I proved it: replaced the shader with an instrumented version that does an OpImageFetch with a hardcoded texel coord on the bound image. The descriptor index read identical (860) at a dot pixel and a clean pixel right next to it, but the fetch returned completely different values. A fetch with a literal coord has to be invocation invariant, so the descriptor at that slot was resolving to a different physical texture per pixel. Wrong descriptor broadcast, case closed.
Fix: decorate the index operand and the access chain pointer with NonUniform too, not just the loaded value, at every dynamically indexed descriptor site (image load/store/atomic plus sampled image, combined and separate sampler paths). A/B tested on device, with only the existing loaded-value decoration the dots persist, with the full decoration they're gone. If you test this, bump the shader cache version or clear the cache first, otherwise you're replaying stale SPIR-V and it'll look like it didn't work.
That's it. Happy to go deeper on any of them in comments.