Files
nxnative-easy/dm/third_party/ryujinx/README.md
T
seeddsandb1tdr3amer24 99d0aae38f Keep bindless reads through mixed handle phis; read misaligned buffer textures through an aligned copy (#168)
Two general causes of FINAL FANTASY RESONANCE's missing fires, smoke and muzzle
flashes, found and first fixed by b1tdr3amer24 (GitHub issue #168).

- Translator (vendored BindlessElimination.cs, TryTableHandle): a texture read
  whose handle phi mixes c2 handle words with values that are not handles
  (undefined, or float values the compiler kept in the register on paths where
  the predicated read does not run) was removed and its result set to 0:
  58,122 reads in FINAL FANTASY RESONANCE, mostly Niagara particle vertex
  factories, whose meshes collapsed to a point. The read now takes the c2
  handle among the inputs, or reads each candidate and picks by the phi's run-
  time value; candidates read elsewhere as another texture shape are left out
  (a second sweep, ResourceManager.GetTextureTypes). Only phis that
  GenerateBindlessAccess refuses come here, so tex_dyn_slots arrays keep their
  path: the other 69,449 shaders' SPIR-V is unchanged. Several candidates are
  never used for an image store or atomic. dmsh_xlate's Log now reaches the
  notes as "translator: ..." and the build summary counts those apart.
- Host (nvn_mtl.m, tbuf_shadow): a texture buffer view at an offset that is
  not 16-byte aligned reads from the boundary below on an M4 Pro (t_tbuf_align:
  56 of 56 views wrong; the M6 measurement in the old comment does not hold).
  Such views are read through a per-submission aligned copy; aligned views are
  untouched. A workaround for the Metal limit, its gaps (GPU writes in the same
  submission, CPU_NO_ACCESS pools, image writes) recorded as open.

Translator rebuilt; lock and chain header updated. Checked: all FFR shaders
translated before and after; FFR on the Mac (fires and smoke column render,
steady; with the copy off they flicker); gfx, chain and docs tests.

Co-authored-by: b1tdr3amer24 <240231594+b1tdr3amer24@users.noreply.github.com>
2026-10-26 23:43:09 +08:00

4.5 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 OpCompositeConstruct and passed as Offset. A four-offset gather becomes four one-offset gathers, each giving component w. Upstream wrote them as an OpConstantComposite with ConstOffset(s), which is invalid SPIR-V; SPIRV-Cross threw nullptr and the shader never built (2026-10-18: 8 shaders in Wonder, Link's Awakening, Tears of the Kingdom and Age of Calamity). Marked nxnative: in the code.
    • Texture coordinates that are NaN are replaced by 0 (the nfZero select). This came with the first import.
  • 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 two constant buffer | constant handles 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). Marked nxnative: in the code.

  • The same file, TryTableHandle and IsBindlessHandleAllowed, with Translation/Optimizations/Optimizer.cs (a second sweep) and Translation/ResourceManager.cs (GetTextureTypes): a handle phi that GenerateBindlessAccess refuses, because some inputs are not handles (undefined, or values kept in the same register on paths where the predicated read does not run), takes the c2 handles among its inputs. With one, it takes the phi's place; with several, one read per handle, and the result is chosen by comparing the phi's value with each handle at run time. Upstream removed such reads and wrote 0: 58,122 reads in FINAL FANTASY RESONANCE (2026-10-26, GitHub issue #168). See Bindless reads whose handle phi also carries other values. Marked nxnative: in the code.

  • Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs, EmitTex (TLD 1D with integer coordinates only) and EmitTexs (TLDS Texture1DLodZero), with IGpuAccessor.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.m tbuf_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). Marked nxnative: in the code.

  • Ryujinx.Graphics.Shader/Translation/EmitterContext.cs and Translation/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.

  • Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs, IntermediateRepresentation/TextureFlags.cs and CodeGen/Spirv/Instructions.cs: the MSL 2.3 path bounds image atomics before forming the texel pointer. Returning IGN atomics preserve the old texel on the valid edge and return zero outside the image; CAS, predicate results and non-IGN modes remain rejected. See bounded MSL 2.3 atomic emulation, found on SHIN MEGAMI TENSEI V: Vengeance's particle counters.

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.