Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dm/gfx/nvn/dmsh_chain.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Generated file (dm/gfx/tools/dmsh_chain.py --header): the B shader library translation chain version this source tree expects (default options), one for every game;
// the host loads only <library dir>/b-<V>/. Run dmsh_chain.py --header after changing the chain's tools and commit this file with the change
#define DMSH_CHAIN "d403eb0683df"
#define DMSH_CHAIN "cdef7a05ad69"
14 changes: 14 additions & 0 deletions dm/gfx/tests/test_dmsh_ampere_mem.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ def test_another_form_is_refused(self):
self.assertIn('0x925 form 2', log)


@unittest.skipUnless(os.environ.get('DMSH_TEST_XLATE'), 'set DMSH_TEST_XLATE to the offline translator')
class ShadingRate(unittest.TestCase):
"""S2UR of system register 0x84, the fragment's size in pixels (X in bits 8..15, Y in 16..23), as Nintendo Switch Sports Resort's sea shaders encode it (2271b2e0293b3c55 +0x2600):
the host shades every pixel, so 1 x 1. It read 0 as an unknown register, and the sea's colour, divided by the fragment's area, was NaN"""
run_job = PixelCovered.run_job
SPH = PixelCovered.SPH
S2UR = (0x000e220000008400, 0x00000000000479c3) # S2UR UR4, SR 0x84
I2F_R0 = (0x03ffe20008201400, 0x0000000400007c45) # I2F R0, UR4 as the game reads it (+0x2d90), waiting on every barrier: colour 0's x, 65792 for 1 x 1

def test_reads_one_by_one(self):
msl, log = self.run_job(self.S2UR, self.I2F_R0)
self.assertIsNotNone(msl, log)
self.assertIn('float(65792)', msl) # 0 before (an unknown system register)

@unittest.skipUnless(os.environ.get('DMSH_TEST_XLATE'), 'set DMSH_TEST_XLATE to the offline translator')
class DepthRegister(unittest.TestCase):
"""A pixel shader's depth output follows its colours at four registers per enabled render target, then the sample mask register. Ocarina of Time's agl_common depth pass
Expand Down
6 changes: 3 additions & 3 deletions dm/gfx/tools/dmsh_chain.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Translation chain tool fingerprints (written by tool_lock.py --update-lock; regenerate after changing tools and commit it)
dmsh_xlate.dll f2d1a53df023344a
Ryujinx.Graphics.Shader.dll cbb2a0c24869eefa
Ryujinx.Common.dll ffe1bca8ca60ee61
dmsh_xlate.dll 852359e6a7f8b536
Ryujinx.Graphics.Shader.dll e0290d86b5577c98
Ryujinx.Common.dll c7032c0b587a4493
xlate_source 8986080b40b79cab
spirv-cross e37945d8e441d34d
metal_macosx Apple metal version 32023.922 (metalfe-32023.922.4)
Expand Down
Binary file modified dm/gfx/tools/dmsh_xlate_bin/Ryujinx.Common.dll
Binary file not shown.
Binary file modified dm/gfx/tools/dmsh_xlate_bin/Ryujinx.Graphics.Shader.dll
Binary file not shown.
Binary file modified dm/gfx/tools/dmsh_xlate_bin/Spv.Generator.dll
Binary file not shown.
Binary file modified dm/gfx/tools/dmsh_xlate_bin/dmsh_xlate.dll
Binary file not shown.
Binary file modified dm/gfx/tools/dmsh_xlate_bin/dmsh_xlate.pdb
Binary file not shown.
2 changes: 2 additions & 0 deletions dm/third_party/ryujinx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ Three projects from Ryujinx 1.3.2: `Ryujinx.Graphics.Shader`, `Ryujinx.Common` a

- `Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs` (`TryGenerateBoundedUniformLoad`), `Translation/ResourceManager.cs`, `StructuredIr/ShaderProperties.cs`, `Constants.cs` and `Translation/TranslationFlags.cs`: the Metal path (`TranslationFlags.MetalUniformBounds`) gives 0 for a read of a game uniform slot (c[3] to c[16]) past the size the game bound, as Maxwell does, comparing the word's index with the slot's size from a table in bank 25 that the host fills. Upstream relied on Vulkan's robust buffer access, which Metal does not have. See [reads past a uniform binding's size](../../../docs/reference/shaders.md#reads-past-a-uniform-bindings-size), found on Paper Mario: The Thousand-Year Door (GitHub issue #1860).

- `Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs` and `Instructions/InstEmitMove.cs` (`EmitSReg`): system register 0x84 (`SReg.VariableRate`, the fragment's size in pixels, X in bits 8..15 and Y in bits 16..23) reads 1 x 1, as the host shades every pixel. It read 0 as an unknown register, and Nintendo Switch Sports Resort's sea divided by the area: NaN, a black sea

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>.
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ enum SReg
CircularQueueEntryIndex = 97,
CircularQueueEntryAddressLow = 98,
CircularQueueEntryAddressHigh = 99,
VariableRate = 132,
}

enum RoundMode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ private static Operand EmitSReg(EmitterContext context, SReg sreg)
src = ConstF(1); // TODO: Use value from Y direction GPU register.
break;

// The fragment's size in pixels: X in bits 8..15, Y in bits 16..23 (Mesa NAK's NAK_SV_VARIABLE_RATE). The host shades every pixel, so 1 x 1: the 0 an
// unknown register reads made the area 0 and what a shader divided by it infinite (Nintendo Switch Sports Resort's sea came out black)
case SReg.VariableRate:
src = Const(0x00010100);
break;

case SReg.ThreadKill:
src = context.TranslatorContext.Definitions.Stage == ShaderStage.Fragment ? context.Load(StorageKind.Input, IoVariable.ThreadKill) : Const(0);
break;
Expand Down
1 change: 1 addition & 0 deletions docs/agents/symptoms.md
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@ One line per symptom in the [subsystem references](../reference/): what you see
- the scene goes white with a yellow fringe: a few objects hold the largest value their target can, and bloom spreads it over the picture. Clamping a shader's terms one by one finds a value that is a register's stale contents. Or characters lit from an environment cube turn bright white in certain places only, and the cube's mean is far above its value elsewhere. → [A deferred write under a false guard](../reference/shaders.md#a-deferred-write-under-a-false-guard)
- `Ampere instruction f63` (or `f6c`, `364`, `367`) `is not implemented`, or `SURED form 0310e000`, in the build. → [Ampere forms with a handle in a register, and SURED's other operations](../reference/shaders.md#ampere-forms-with-a-handle-in-a-register-and-sureds-other-operations)
- `Ampere instruction 21b at … is not implemented` (`…0405721b`) or `Ampere instruction 925 at 0x0 is not implemented` (`040e0200000e4000 …7925`) in the build. → [Ampere BMSK and the read of a covered pixel](../reference/shaders.md#ampere-bmsk-and-the-read-of-a-covered-pixel)
- a Switch 2 game's water or another full-screen surface draws black (or as a flat dark colour under the fog) while its normals and depth are right; a texture dump of the target shows the colour channel at 0 where the surface is, and building the shader without fast maths changes nothing. → [The fragment's shading-rate size reads 1 x 1](../reference/shaders.md#the-fragments-shading-rate-size-reads-1-x-1)
- no wrong picture seen so far. In the MSL, a shader with a 0x886 vote has `if (false)` and `false ? a : b` where a uniform predicate guards a value or a branch, and a lane guard on the same number reads `simd_all` or `simd_any` of its own predicate. → [VOTEU writes the uniform predicate](../reference/shaders.md#voteu-writes-the-uniform-predicate)
- `[RED] <key>: the translator deleted N bindless accesses` in the build (Losses a shader build reports; `Failed to find handle source for bindless access` in its reflection's notes), for a shader with TXD through a uniform register (0xf6c). The MSL has no gradient sample, and what it read comes back 0. → [TXD through a uniform register kept no handle](../reference/shaders.md#txd-through-a-uniform-register-kept-no-handle)
- `Failed to find handle source for bindless access` in the build's translator notes, for a read whose handle is two words of the game's own uniform buffer, and what it read comes back 0. Or nothing in the log: the read binds `fp_t_cb3_<word>` or `fp_t_cb2_<word>`, a texture word with no sampler word, so its sampler is `samp_tex`'s guess, where the shader's other reads of that word bind both. → [Handles built under a guard the read's guard cannot be tied to](../reference/shaders.md#handles-built-under-a-guard-the-reads-guard-cannot-be-tied-to)
Expand Down
8 changes: 8 additions & 0 deletions docs/reference/shaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,14 @@ Finding, keying and translating shaders (`dm/gfx/tools/shader_split.py`, `dmsh_b
- **Fix:** `ABmsk` follows PTX's `bmsk` definition, its `.W` at bit 75 as SGXT's (only the clamping form has been seen). `APixelCovered` loads a new `IoVariable.HelperInvocation`, Metal's `simd_is_helper_thread()`, as an integer; any other form of 0x925 stays refused (chain change). `test_dmsh_ampere_mem.py` covers both.
- **Found on:** [Star Fox](../../dm/games/0400E88025B1A000/README.md): 1 compute and 2 pixel shaders, none asked for in play so far, so neither instruction has run. Neither opcode is in the shaders of Donkey Kong Bananza, Splatoon Raiders, Mario Tennis Fever or Pokopia.

### The fragment's shading-rate size reads 1 x 1

- **Symptom:** a Switch 2 game's water or another full-screen surface draws black (or as a flat dark colour under the fog) while its normals and depth are right; a texture dump of the target shows the colour channel at 0 where the surface is, and building the shader without fast maths changes nothing.
- **Cause:** S2UR of system register 0x84 (Mesa NAK's `NAK_SV_VARIABLE_RATE`): the fragment's size in pixels, X in bits 8..15 and Y in bits 16..23, which variable rate shading makes 2 or 4. The translator did not know the register and gave 0, the default for an unknown one. Nintendo Switch Sports Resort's sea shaders divide a blend weight by the fragment's area: 0, an infinite weight, and the colour came out NaN, which `blend_zero` (`dm_az`) writes as 0.
- **Fix:** `SReg.VariableRate` (132, `Decoders/InstDecoders.cs`) reads `0x10100` in `EmitSReg` (`Instructions/InstEmitMove.cs`): the host shades every pixel, so 1 x 1 (chain change).
- **Found on:** Nintendo Switch Sports Resort (`04008E001F098000`, v65536; no profile yet): 612 of its 11,059 shaders, all pixel shaders, read the register; its title screen's sea was black and draws blue with the change, on the Mac.
- **Check:** `test_dmsh_ampere_mem.py` (`ShadingRate`, with `DMSH_TEST_XLATE`).

### VOTEU writes the uniform predicate

- **Symptom:** no wrong picture seen so far. In the MSL, a shader with a 0x886 vote has `if (false)` and `false ? a : b` where a uniform predicate guards a value or a branch, and a lane guard on the same number reads `simd_all` or `simd_any` of its own predicate.
Expand Down
Loading