diff --git a/runtime/gfx_shader.c b/runtime/gfx_shader.c index 3628ce27..85fa0571 100644 --- a/runtime/gfx_shader.c +++ b/runtime/gfx_shader.c @@ -1485,10 +1485,14 @@ static const GfxShader *translate_one(const Req *r, int stage, const uint8_t *co build_request(req, hex, r->stage_name, code_path, r->c1, r->c1_len, a, control); int ok = svc_request(req, reply, sizeof reply); // NX2NAVI_XLATE_KEEP=1: a last-frame variant's job stays as .job (one request line) with its code, to run the - // translator on by hand (nx2navi_xlate --serve < .job) + // translator on by hand (nx2navi_xlate --serve < .job); 2 keeps every job translated in this run (delete a + // key's .res.json and .spv from the cache to have it translated, and kept, again) static int keep = -1; - if (keep < 0) keep = rt_knob("XLATE_KEEP", "0"); - int kept = keep && a && a->mvprev; + if (keep < 0) { + const char *k = cfg_get("NX2NAVI_XLATE_KEEP"); + keep = k && *k ? atoi(k) : 0; + } + int kept = keep >= 2 || (keep && a && a->mvprev); if (kept) { char job_path[PATH_CAP + 80]; snprintf(job_path, sizeof job_path, "%s/%s.job", cache_dir, hex); diff --git a/tools/build_xlate.py b/tools/build_xlate.py index b4655775..2e0768f1 100644 --- a/tools/build_xlate.py +++ b/tools/build_xlate.py @@ -99,8 +99,8 @@ def prepare_sources() -> Path: for junk in list(src.glob("src/*/obj")) + list(src.glob("src/*/bin")): shutil.rmtree(junk) patches = sorted((XLATE / "patches").glob("*.patch")) - if len(patches) != 27: - sys.exit(f"expected 27 patches, found {len(patches)}") + if len(patches) != 28: + sys.exit(f"expected 28 patches, found {len(patches)}") for patch in patches: # git apply works outside a repository when given a directory; --check first so a failure names the patch. for extra in (["--check"], []): diff --git a/tools/xlate/patches/0029-more-storage-buffer-slots.patch b/tools/xlate/patches/0029-more-storage-buffer-slots.patch new file mode 100644 index 00000000..1a5191a0 --- /dev/null +++ b/tools/xlate/patches/0029-more-storage-buffer-slots.patch @@ -0,0 +1,60 @@ +--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs ++++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs +@@ -281,7 +281,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations + } + else + { +- Utils.DeleteNode(node, operation); ++ // NX2NAVI: the store becomes an unused copy in place instead of leaving the list: the ++ // loop goes on from node.Next, which a removed node no longer has, so every global ++ // access after it in the block stayed global and failed the whole translation. ++ for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) ++ { ++ operation.SetSource(srcIndex, null); ++ } ++ ++ node.Value = new Operation(Instruction.Copy, Local(), Const(0)); + } + } + else +--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs ++++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs +@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Shader.Translation + + private readonly SetBindingPair[] _cbSlotToBindingMap; + private readonly SetBindingPair[] _sbSlotToBindingMap; +- private uint _sbSlotWritten; ++ private ulong _sbSlotWritten; + + private readonly Dictionary _sbSlots; + private readonly Dictionary _sbSlotsReverse; +@@ -66,7 +66,10 @@ namespace Ryujinx.Graphics.Shader.Translation + _stagePrefix = GetShaderStagePrefix(stage); + + _cbSlotToBindingMap = new SetBindingPair[32]; // NX2NAVI: slots 18-31 for Transforms/MotionPrevious.cs +- _sbSlotToBindingMap = new SetBindingPair[16]; ++ // NX2NAVI: 64 storage buffer slots (the width of _sbSlotWritten), not 16: Ocarina's NVN2 compute programs ++ // reach more than 16 buffers through their pushed pointers and pointer tables, and every access to a buffer ++ // past the 16th found no slot. ++ _sbSlotToBindingMap = new SetBindingPair[64]; + _cbSlotToBindingMap.AsSpan().Fill(new(-1, -1)); + _sbSlotToBindingMap.AsSpan().Fill(new(-1, -1)); + +@@ -193,7 +196,7 @@ namespace Ryujinx.Graphics.Shader.Translation + + if (write) + { +- _sbSlotWritten |= 1u << slot; ++ _sbSlotWritten |= 1ul << slot; + } + + binding = setAndBinding.Binding; +@@ -503,7 +506,7 @@ namespace Ryujinx.Graphics.Shader.Translation + if (setAndBinding.Binding >= 0) + { + (int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key); +- BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None; ++ BufferUsageFlags flags = (_sbSlotWritten & (1ul << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None; + descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags); + } + }