nvn-wire · git:20261108.3925321 · 2026-11-08 · sha256 b818af606d0818e9
nvn-wire git:20261108.3925321A
Immutable. This exact content never changes and is served at /api/v1/blob/b818af606d0818e9.
--- name: nvn-wire description: S2Arm 的 NVN 语义与教训参照:实现或修零配置直连 NVN 前端(graphics/nvn)里任何一个 NVN 函数、对象或命令之前先查本 skill 的 references/。附带从小菠萝(三周 NVN→Metal 实战)、S2Arm 通用方案、丝之歌试点三处提炼的全部参照和教训。「施工流程」一节是 10-24 停用的单款接线(C 档)的历史流程,只作对照,不再新做。 --- # NVN 语义与教训参照(附:单款接线历史流程) **现行做法**:main 上的 NVN 前端是零配置直连(`graphics/nvn/gfx/nvn/hle_nvn.c` 接 NVN 函数、`graphics/nvn/gfx/nvn/nvn_mtl.m` 翻成 Metal),对所有 NVN 游戏通用,不按款配置(见 docs/方案_快速通用模式.md 与 docs/方案.md §2 铁律)。缺函数、语义不对,就在这两个文件里按 references/nvn_semantics.md 的语义补齐,并按 [skills/gfx-triage](../gfx-triage/SKILL.md) 写先红后绿的单测(graphics/nvn/tests/)。 **历史**:下文「施工流程」描述的是 10-24 前的单款接线(C 档):NVN 调用译成 Ryujinx IRenderer,代码在 origin 分支 `wire/silksong-c`(graphics/wire + runtime/src/wire.c)。那条路已被零配置直连取代,按款启用与「通用层零专用配置」铁律冲突,**不进 main、不再新做**。流程里的侦察、真值对拍、逐函数补齐的方法对修直连前端仍有参考价值,命令只在该历史分支上能跑。 说明:文中「小菠萝」是 S2Arm 的内部前身实现,代码未公开。references 里带 `H:` / `M:` 行号的出处只供内部对照;外部贡献者看语义描述就够了。 ## 参照(按需查,不要整篇读) | 文件 | 内容 | 什么时候查 | |---|---|---| | references/nvn_semantics.md | 逐对象、逐命令的 NVN 语义,小菠萝实现位置,S2Arm 现状与差异,⚠ 易错点 | 实现或修任何一个 NVN 函数之前 | | references/xbl_lessons.md | 小菠萝三周 152 条教训(着色器缓存、驻留、上屏节拍、iOS 真机、功耗、调试方法) | 遇到对应阶段的问题;开工前先读最后的「最值钱 10 条」 | | references/s2arm_lessons.md | S2Arm 通用方案 167 条(Metal 后端约束、首遇、GC、Mac 局 / 真机 / 门禁 / 列车用法) | 同上;开工前先读最后的「必须知道的 10 条」 | | references/pilot_silksong.md | 丝之歌试点 22 个实测坑(构建缓存键、方向坐标、控制段、按阶段绑程序……)和停点 | 开工前通读,只有 40 行 | **开工前必读**:上面三份文件里的「10 条」各一遍,加 pilot_silksong.md 全文,约 15 分钟。这一步省掉的是几个小时的踩坑。 画面出错(花屏、不满屏、直连异常)时的分诊另见 [skills/gfx-triage](../gfx-triage/SKILL.md)。 ## 施工流程(历史:单款接线,只在 wire/silksong-c 分支上能跑) ### 1. 起手(约 10 分钟) 1. 工作树:`git -C <S2Arm 仓库> fetch origin && git -C <S2Arm 仓库> worktree add <工作树目录>/<名> origin/wire/silksong-c -b wire/<款>`。分支落后 main 时**按列车的方向**合:`git checkout --detach origin/main && git merge <本支>`;冲突如果出在 Ryujinx 补丁 series / 改动清单上,跑 `python3 tools/train_renumber.py "$PWD"` 续号(它会自己提交),再 `git branch -f <本支> HEAD && git checkout <本支>`。⚠ 别在本支上 `git merge origin/main` 再续号:工具默认「当前 = main」,会把 main 上已有补丁的号改掉(10-24 实测)。其他冲突照常手解。 2. 私有产物根(公共现行根会被别人换掉):`python3 tools/clonedir.py "$(cd -P <产物根目录>/<款>@现行 && pwd)" <私有产物根目录>/<名>/<款>` 3. 侦察:`python3 graphics/wire/tools/nvn_recon.py <私有根>`,得到程序号、这款按名字取的 NVN 函数全集、还没实现的(按对象分组)、包里有没有着色器缓存。没有缓存就先让通用路径给这款出包。 4. 编译:`S2A_CS=1 make -s host`。 5. 真值局与第一个接线局同根、同参数、关输入,排队一起跑: - `bash graphics/wire/tools/wirerun.sh <款> <私有根> <出>/truth 90 1-1800 off` - `bash graphics/wire/tools/wirerun.sh <款> <私有根> <出>/w1 60 1-1500` ### 2. 补函数:侦察结果 → 实现,在第一局之前完成 - 侦察列出的「没实现」里,凡是 nvn_semantics.md 标为小菠萝已实现的,照它的语义一次补齐。getter、调试标签一类直接补,不用等跑局报红。 - nvn_semantics.md 最后一节列着两类缺口,这款用到的先补: - 小菠萝有而 S2Arm 没有的 27 个函数(事件整组、ClearTexture、ReadTexels 等); - 表里有、但回放没做或会报红的 7 处(CopyTextureToBuffer、Downsample、ResetCounter、多重采样回放、深度偏移回放、整数清色、驱动段 c0/c2)。 同节的 25 条「S2Arm 差异」逐条判断对本款有没有影响。 - 写法:`[UnmanagedCallersOnly] static <返回> <去掉 nvn 前缀的名字>(…)`,签名写在一行里,放进 WireApi.cs / WireCmd.cs;回放放进 WireReplay.cs。补完跑 `python3 graphics/wire/gen_table.py`。 - 枚举值、缺省值逐个查仓库里的 `graphics/nvn/gfx/nvn/include/nvn.h`;GAL 方法签名逐个查 `compat/tree/src/Ryujinx.Graphics.GAL`。 - 补完派一个审查子 Agent,把这批新增和改动对照 nvn_semantics.md 逐函数审,「确定」的问题全部改完再跑局。提示词模板见文末。 ### 3. 调试循环(每局 45–60 秒,一局合并多项修正) wirerun 会输出:「近况」行(出图、绘制、跳过原因、着色器命中)、上屏参数、崩溃栈、红行分类汇总。按下面的顺序处理: 1. **崩溃** → 看栈。Metal 断言要在调 GAL 之前就拦住并报红,不能让进程崩。 2. **「NVN 未实现被调用」** → 按 nvn_semantics.md 补。 3. **跳过绘制 > 0** → 按括号里的分类逐类清(没程序 / 图元 / 索引 / 复合 / 着色器未命中)。 4. **全黑、颠倒、偏移** → 拿接线局与真值局 host.log 的「出图参数」行逐字段比(贴图尺寸、源矩形、翻转),再对照 pilot_silksong.md 的方向坐标三条。 - ⚠ 现在的视口 (x, y+h, w, −h) 加正面绕序对调,是丝之歌(窗口原点左上)实测出来的口径。 - 新游戏先看接线局日志里的「窗口原点」行。如果是左下(GL),要按 Ryujinx StateUpdater.UpdateViewportTransform / UpdateFrontFace 重新推一遍,再拿真值的「出图参数」核对,不能直接沿用。 5. **局部缺失** → 先用 `S2A_WIRE_RTLOG=<帧>` 画出离屏链路:每次换目标、每次绘制采样了哪张贴图、贴图在哪一帧建、小目标(查找表)在哪一帧被写。再用 `S2A_WIRE_SHOWTEX=<贴图号,…>` 按帧轮换上屏这些中间贴图,找到最后一张对、第一张错的那一环,只修那一环。 6. 同一类错误出现两次 → 再派一次审查子 Agent,覆盖这一整类,不要逐个撞。 ### 4. 验收与合入 - 逐帧:`python3 tests/visual/wire_cmp.py <truth>/framecap.bin <wN>/framecap.bin --logs <truth host.log> <wN host.log>`。用块指标加单调对齐比较,要求新增红行为 0。两局本来就不会逐像素相同,真值局的存帧窗口要比接线局长。 - 进局:用通用自动玩家(AI 看屏驾驶)走到 MARK;同一款第二局起回放学过的路线,两边进局路径一致,再比一次。 - 缺省关一致:`make native-test-wire`,加上通用层原有门禁全绿。 - 合入:外部贡献者按 docs/协作循环.md 提 PR,并贴 `bash tools/contrib_check.sh` 摘要;维护者在列车里合。 - iPhone:同一个包,A/B 只差 `S2A_WIRE`,读数只认 iPhone;交出「期望 → 真结果」表。 ### 5. 汇报节奏 每个里程碑报一次:起手完成 / 首帧有图 / 标题与真值一致 / 进局到 MARK 一致 / iPhone A/B。每次附墙钟和用量。卡住超过 1 小时就报「做到哪 / 卡在哪 / 还要什么」。 ## 诊断开关(历史:接线分支的 graphics/wire/WireReplay.cs) - `S2A_WIRE_RTLOG=<帧>`:该帧的换目标、每次绘制采样的贴图、建贴图;小目标(高 ≤ 32)在任何帧都记。 - `S2A_WIRE_SHOWTEX=<号,…>`:上屏按帧轮换显示中间贴图。接线局与真值局的帧号不对应,接线局启动更快。 - `S2A_WIRE_REUPLOAD=1`(每帧重传池内容)、`S2A_WIRE_NODEPTH=1`(关深度测试):快速二分用。 - 「近况」行里有跳过原因分类、对象号解析不出、无标记视图等计数,「不许静默成功」靠这些计数和报红桩。 ## 审查子 Agent 提示词模板 > 全程中文思考与报告。只读审查,不改文件、不跑局。 > > 审查对象:S2Arm 接线层 graphics/wire(NVN → Ryujinx IRenderer)。 > - 语义参照 skills/nvn-wire/references/nvn_semantics.md。 > - NVN 枚举以仓库 graphics/nvn/gfx/nvn/include/nvn.h 为准,不看任天堂官方 SDK 文档。 > - GAL 接口在 compat/tree/src/Ryujinx.Graphics.GAL。 > > 本款侦察结果与本轮改动:<贴 nvn_recon 输出与 git diff --stat>。 > > 逐函数找会导致画面错 / 黑 / 崩的语义差异,重点看: > - 渲染目标与清屏;贴图拷贝与上传; > - 混合与颜色掩码;深度模板;剔除与正面朝向;视口方向; > - 顶点与索引;常量缓冲与 support buffer; > - 贴图 / 采样器句柄与池;窗口与上屏。 > > 每条给出「文件:行号、我的写法 → 参照语义 → 后果 → 改法」,按最可能致黑排序,区分确定 / 可疑,1500 字以内。