mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Give the translator 64 storage buffer slots and keep it converting a block after a store it cannot place.
Ocarina's NVN2 compute programs reach more than 16 buffers through their pushed pointers and pointer tables; past the 16th the translator found no slot, dropped the store, and its loop then read the next node of a node it had just removed, so every later global access in the block stayed global and the whole program failed with "Invalid storage kind GlobalMemory". Ten compute programs of Kokiri Forest were skipped on every dispatch and retried on every one, which also cost 10-25 ms frames. Now one program still fails (an Ampere MATCH instruction the lowering does not handle). NX2NAVI_XLATE_KEEP=2 keeps every translated job with its code for running the translator by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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 <key>.job (one request line) with its code, to run the
|
||||
// translator on by hand (nx2navi_xlate --serve < <key>.job)
|
||||
// translator on by hand (nx2navi_xlate --serve < <key>.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);
|
||||
|
||||
@@ -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"], []):
|
||||
|
||||
60
tools/xlate/patches/0029-more-storage-buffer-slots.patch
Normal file
60
tools/xlate/patches/0029-more-storage-buffer-slots.patch
Normal file
@@ -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<int, int> _sbSlots;
|
||||
private readonly Dictionary<int, int> _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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user