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.

reddit.com
u/lit1337 — 22 hours ago
▲ 54 r/EmuDeck

Ryudeck, a Steam Deck-focused Ryujinx fork. It's early, it's rough, and it's just me. Looking for testers and help.

I've been working on Ryudeck, a hard fork of Ryujinx aimed at the Steam Deck specifically instead of trying to run on everything. I wanted a Switch emulator that actually feels like it belongs on the Deck: controller-driven UI, an in-game quick-settings blade, and Vulkan/RADV tuning for the VanGogh GPU, instead of a desktop app you wrestle onto it.

To be upfront about where it is: it's early, and it's a one-person project. Some games run well, some have problems I'm still working through, and I can't test much alone since I have one Deck and limited time. There will be rough edges.

That's really why I'm posting. Two things I could use.

Testers. If you have a Deck and your own legally dumped games, keys, and firmware, give it a try and tell me what breaks. Crashes, glitches, games that won't boot. A bug report with a log helps a lot more than "doesn't work".

Help. If you know your way around Vulkan/RADV, .NET, or Switch emulation internals and feel like poking at it, I'd really appreciate the hand. It's a lot for one person.

No games, ROMs, firmware, or keys are included. You bring your own dumps. It can import them from an existing Ryujinx, yuzu, or Eden install if you already have one set up.

Code and downloads: https://github.com/deucebucket/ryudeck

Latest build: https://github.com/deucebucket/ryudeck/releases/latest

What runs so far, real screenshots: https://github.com/deucebucket/ryudeck/wiki/Compatibility

It's built on Ryujinx and owes everything to that project. I'm not selling anything, just putting it out there and hoping a few people want to try it. Thanks for reading.

reddit.com
u/lit1337 — 11 days ago

Has anyone tried running retrieval inside the model, not before it?

Been messing with a bolt-on refiner block for small models. Insert a small trainable transformer layer at the midpoint of a frozen base model, loop it 2-4 times over the hidden states. Base model never changes.

SmolLM-135M: 23.5 -> 17.5 PPL (-25%) with 2M extra params. Qwen2.5-3B, PyTorch: ~10.0 -> ~8.5 PPL (-15%) with 33M extra params. Qwen2.5-3B, C++ port in llama.cpp: 8.58 -> 8.31 PPL (-3.1%) so far, two blockers remain before matching PyTorch.

Gate needs a straight-through estimator. Init at anything negative and it starves. Force 100% during training, let it float at inference.

First version was shared collapsed layers, no refiner. PPL 120,654. Dead. C++ port first run: 49M PPL. Weights were on CPU, GPU read garbage. Fixed with ggml_backend_alloc_ctx_tensors_from_buft on the same CUDA backend. Attention kept crashing on ggml_mul_mat with 3D tensors until I switched to build_attn_mha. Causal mask still broken (null GPU tensor data). distrobox cmake caches stale builds. Manually compiling .o files now.

My Question:

The refiner has a gated injection point mid-model with a 2-4 pass loop. What if you stuck a tiny projection layer there to query an external vector index from inside the model's hidden state? Not at the prompt level. From the representation space. Each loop could re-query with a more informed state. Would this even work? Would the retrieval noise kill the signal? What would the training setup look like?

Haven't built this part yet. But the architecture already has a place for it and the pieces are small enough to test on a single card. Anyone tried something similar?

reddit.com
u/lit1337 — 27 days ago

Of all the books and all the pages.

I'm glad they cut it off just in time lol

u/lit1337 — 2 months ago