☰
Pinyon Shift 原生渲染器深度解析:从PM4命令流到EDRAM、Resolve与纹理解码的完整指南
2026/11/6 6:28:33 网站建设 项目流程

【免费下载链接】pinyon-shift

A playable preview of Forza Horizon static recompilation

项目地址:https://gitcode.com/gh_mirrors/pi/pinyon-shift
点击查看免费下载

Pinyon Shift 把 Xbox 360 版《Forza Horizon》重新编译为 PC 原生程序,其核心是一套专为这款游戏打造的原生渲染器:它不再模拟 Xenos GPU,而是直接解读游戏发出的 PM4 命令流,在 Vulkan 上执行 EDRAM 表面管理、Resolve 与纹理解码,让游戏在 1x 到 4x 分辨率下以显示器刷新率运行。这篇文章带你完整看懂这条渲染链路。

为什么不用通用模拟,而要"游戏专用"渲染器

项目最初基于 ReXGlue(Xenia 衍生)的 Xenos 模拟渲染器,帧率只有约 28 fps。团队换了思路:先对游戏实际发给 GPU 的内容做一次完整"普查"(census)——在 17,580 帧脚本化路线上逐帧统计,而不是猜测。结果是:游戏只用极其有限的 GPU 特性集——

游戏使用的特性数量
渲染目标配置(Render target configurations)29 种(后续路线 +11)
Resolve 种类20 种(+10)
纹理格式与维度组合22 种
每个 draw 的颜色目标固定 1 个(无 MRT)
图元类型三角带、列表、四边形、点、矩形
内存导出(memexport)draw0
前缓冲恒为 1280×720、10:10:10:2

有限且可枚举的"帧契约",意味着可以写一个只处理这套配置、其余一律记录原因并拒绝的渲染器。这套契约记录在 NATIVE_FRAME_CONTRACT.md;某模式只有在整条路线上"跳过计数为零"时才算被覆盖。

PM4 命令流:解码、录制、提交三条流水线

游戏的 GPU 命令以 PM4 数据包的形式写入命令环。几乎全部 draw 都以PM4_INDIRECT_BUFFER形式到达——游戏提前建好了命令缓冲,每帧只是重放;实测每帧约 5,000 个 draw 中只有 42 个来自即时发射器,且 96% 的间接缓冲在相邻帧间字节级一致。

渲染器把这拆成多个职责清晰的线程:

线程职责
Guest render thread游戏自带的 D3D 运行时写 PM4 包
GPU Commands把数据包解码进影子寄存器文件,处理WAIT_REG_MEM,加载微码时做哈希
GPU Recorder持有真正的寄存器状态、缓存与执行器,为每个 draw 推导管线并录制延迟命令流
GPU Submission每 1,024 个 draw 向 Vulkan 提交一次(vkQueueSubmit),并负责上屏
Pipeline / Shader / Storage 工作线程在热路径之外构建管线、翻译着色器、写缓存

顺序是难点:一个比赛帧约有 280 次事件写入、25–30 次 fence 写入、5 次中断和 1 次 swap。fence 写入是"记录"而非"等待",只有当录制线程消费完其之前的全部内容,游戏才能看到 fence。解码与录制拆分后,比赛场景从 17.67 ms 降到 16.46–16.75 ms 每帧。这条链路对应的宿主侧入口在 guest_output_renderer.cpp 和 graphics_hooks.cpp。

EDRAM 表面与转移(Transfer)

Xbox 360 的 Xenos GPU 先画进 10 MB 片上显存 EDRAM,再显式拷出到主存。FH1 原生执行器把 EDRAM 抽象成一张 2,048 个 tile 的所有者地图:

  • 表面(Surface):每个渲染目标是宿主图像,键为 EDRAM 基 tile、pitch、MSAA 模式、深度/颜色与格式,高度延伸到同位置下一个表面;
  • 所有者地图:记录每个 tile 最后被哪个表面写入,以及其 stencil 是否可能非零;
  • 转移(Transfer):当某个 draw 占用别的表面拥有的 tile 时,旧内容必须搬走——颜色走像素 pass,深度走经 word buffer 的 compute pass。没有VK_EXT_shader_stencil_export扩展的显卡(如 NVIDIA)上,深度转移要 9 个 pass。

一个巧妙的优化:对ALWAYS深度测试或不裁剪的 draw,执行器直接在CPU 上跑一遍顶点着色器来圈定覆盖范围,避免"一个 stencil draw 声称占用全部 2,048 个 tile"这类过度保守的转移。转移的瓶颈是 barrier 而非像素量。

Resolve:结果如何回到"游戏可见"的纹理

Xenos 的 resolve 是把 EDRAM 内容显式拷回主存的机制。在 FH1 原生执行器里,resolve 执行一个 compute 着色器,按游戏的分块纹理布局写入一份"游戏内存的宿主镜像",并标记该区间"由 GPU 写过"。随后:

  1. 与该区间重叠的纹理全部失效,下次采样时按请求格式重新解码——一个机制同时覆盖了部分 resolve、多格式别名同一地址、CPU 复用内存等所有情况;
  2. 深度 resolve 必须精确复现打包的 depth+stencil 位,因为后续 draw 会以24_8/24_8_FLOAT读取它(可接受的差异只有 D24S8 舍入的 1 个 LSB 与 float24 低尾数位)。

快速路径叠在其上:resolve 直接写入"当前仍然有效"的纹理(raw-bits 视图),reload 时只重新分块 resolve 改动过的 32 行带。普查还发现唯一的 CPU 回读场景是车辆缩略图(渲染→resolve→CPU 压缩),因此对 256 KiB 以上的一次性 resolve 会在下一个 CPU 可观察命令前拷回游戏内存。20 种 resolve 的完整表格见 NATIVE_FRAME_CONTRACT.md。

纹理解码:从游戏内存到 Vulkan 采样

纹理缓存复用 Xenia 衍生的核心,跑在执行器的内存镜像之上:

  • 键:来自采样常量——基地址、格式、尺寸、pitch、tiling、mip 范围、端序与 swizzle;
  • 解码:compute 着色器做"反分块 + 字节交换",覆盖 DXT1/3/5、DXN、CTX1、DXT3A/5A、10:11:11 以及 16 位归一化与深度格式;不支持 BC 的设备可强制走通用 BC 解码路径;
  • 失效:CPU 写用页写监视(page write-watch)发现,GPU 写由 resolve 标记;靠"每次分配的写入代际"(write generation)而非地址区分。这一细节曾让一条路线的顶点上传量从 41.6 GB 降到 0.42 GB;
  • Gamma:主机的 gamma 纹理用分段线性曲线转换,默认在着色器内精确复现,也可切换更省但中间调偏暗的 sRGB 快速路径。

着色器与上屏:链路的最后两环

  • 着色器:游戏的 Xenos 微码由 ShiftGlue 翻译器转成 SPIR-V。为这款游戏修过三个关键问题:HDR 采样的指数偏置读错字、全像素 quad 才执行的前向跳转、以及带导数 cube 采样改用隐式 LOD+偏置。翻译结果与管线描述跨次保存,设置阶段还会隐藏运行约两分钟的预热路线——空缓存时首帧超预算时间从 13.0 s 降到 5.7 s。着色器语料工具能从光盘的.fxobj文件提取 3,349 个唯一程序,打包为可选的.pnsp格式;相关工具见 shader_capture.cpp 与 SHADER_PACK_FORMAT.md。
  • 上屏:swap resolve 把前缓冲写入镜像,presenter 应用游戏 gamma 曲线与可选 FXAA,再用双线性、CAS 或 FSR 1 缩放;Windows 走 scRGB HDR,Android 走 HDR10 并随面板方向预旋转交换链。
  • 分辨率:1x–4x 为整倍缩放(着色器翻译器把缩放烘焙进去),guest 可见的一切保持游戏尺寸,只有渲染缓冲随倍率放大。

延伸阅读与关键文件

主题位置
帧契约(29 表面 / 20 resolve / 22 纹理布局)NATIVE_FRAME_CONTRACT.md
官方站点渲染器章节renderer.md
每项优化的实测数字gpu-optimizations.md
Xenos 模拟路径的退役记录XENOS_RETIREMENT_BACKLOG.md
早期研究笔记(含失败路线)RESEARCH.md
宿主侧渲染器入口guest_output_renderer.h

Pinyon Shift 原生渲染器最有借鉴价值的经验是:用普查得到的有限契约替代通用模拟——先花两周数清楚游戏到底用什么,再写一个"只处理这些、其余全部拒绝并记录"的执行器。这套方法同样适用于任何静态重编译项目。

【免费下载链接】pinyon-shift

A playable preview of Forza Horizon static recompilation

项目地址:https://gitcode.com/gh_mirrors/pi/pinyon-shift
点击查看免费下载

相关推荐

上一篇:AlgerMusicPlayer 快速上手:本地服务音乐播放器完整指南
下一篇:docker-selenium Firefox 118 镜像标签体系解析:从 tag_and_push_browser_images.sh 输出看版本固定与发布流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询