3.1 KiB
Ryujinx shader translator (vendored subset)
Three projects from Ryujinx 1.3.2: Ryujinx.Graphics.Shader, Ryujinx.Common and Spv.Generator, with these local changes:
-
Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs,GenerateTextureSample:- Texel offsets that are not constants (Maxwell AOFFI / TLD4.PTP offsets read from a register) are built with
OpCompositeConstructand passed asOffset. A four-offset gather becomes four one-offset gathers, each giving component w. Upstream wrote them as anOpConstantCompositewithConstOffset(s), which is invalid SPIR-V; SPIRV-Cross threwnullptrand the shader never built (2026-10-18: 8 shaders in Wonder, Link's Awakening, Tears of the Kingdom and Age of Calamity). Markednxnative:in the code. - Texture coordinates that are NaN are replaced by 0 (the
nfZeroselect). This came with the first import.
- Texel offsets that are not constants (Maxwell AOFFI / TLD4.PTP offsets read from a register) are built with
-
Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs,TryGetOperation/IsSameOperand: a bindless handle that reaches the texture instruction through a phi is followed through the phis that feed it (a handle kept in a loop variable comes back through the loop's own phi), and twoconstant buffer | constanthandles count as the same value. Upstream compared only the phi's direct inputs, so such handles fell to the texture-pool array of 32 (*_t2d_cb0_40000000), which cannot be bound; 218 pixel shaders in Monster Hunter Rise (2026-10-20). Markednxnative:in the code. -
Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs,EmitTex(TLD 1D with integer coordinates only) andEmitTexs(TLDSTexture1DLodZero), withIGpuAccessor.RecordTexelFetch1D: Maxwell reads a 1D texture and a texture buffer with the same instruction, and the bound descriptor decides. When the texture type query does not answer "buffer", the read is translated as 2D at(x & 0x3FFF, x >> 14)instead of(x, 0), and the handle is reported. A 1D texture (one row at most 16384 wide on the host) reads the same; the host binds a texture buffer in such a slot as a linear 2D texture of 16384-texel rows over its memory (nvn_mtl.mtbuf_as_2d). Upstream read(x, 0)and the host had only a dummy texture to give: the light and decal lists of Age of Calamity (at least 15,000 shaders) and Three Houses read zeros (2026-10-21). Markednxnative:in the code. -
Ryujinx.Graphics.Shader/Translation/EmitterContext.csandTranslation/ShaderDefinitions.cs: fixed-input compute lowering explicitly forwards passthrough positions and all captured generic attributes not replaced by the geometry shader, and inherits its output primitive from input topology. Independent offline stages have no next-stage usage mask, and Metal cannot provide the native NV passthrough raster stage. See passthrough compute emission and output bounds.
The shader translation tool in dm/gfx/tools/dmsh_xlate references them to translate the original Switch shaders to SPIR-V.
License: MIT, see LICENSE.txt. Upstream: https://github.com/Ryubing.