KytyPS5 Vulkan渲染管线全解从PM4图形命令流到像素输出的完整GPU模拟链路【免费下载链接】KytyPS5PlayStation 5 emulator for Windows, Linux and MacOS项目地址: https://gitcode.com/gh_mirrors/ky/KytyPS5KytyPS5 是一款支持 Windows、Linux 与 macOS 的PlayStation 5 模拟器其图形子系统的核心任务是把 PS5 主机 GPUGNAD/GFX9 架构发出的PM4 图形命令流逐条解码再通过Vulkan 渲染管线在你的显卡上重放最终输出像素到窗口。本文将沿着一帧数据的完整生命周期拆解这条从guest 内存里的 32 位指令到屏幕上像素的 GPU 模拟链路 一、先看清楚渲染结果下面的画面就是 KytyPS5 的 Vulkan 渲染输出左上角的帧捕获信息Frame / ms / FPS正是宿主侧 Vulkan 交换链在逐帧上报的整条管线可以用一张数据流图概括游戏(AGC驱动) ──写入PM4命令缓冲区──▶ GuestGpu GPU线程 ──▶ CommandProcessor 逐条解码 PM4 ──▶ 更新 HW 寄存器上下文 ──▶ Draw/Dispatch 请求 ──▶ 着色器重编译(AGC→SPIR-V) ──▶ 纹理解Tile 内存页映射 ──▶ Vulkan 命令缓冲录制 ──▶ 提交GPU ──▶ FLIP ──▶ VideoOut/交换链 ──▶ 屏幕像素二、链路入口GuestGpu 独立GPU线程宿主侧图形模拟的入口是 GuestGpu 类源码见 graphicsRun.h。它模拟了 PS5 的图形硬件提交模型独立 GPU 线程构造时启动专用线程m_thread std::jthread(ThreadRun, this)所有 PM4 命令都在该线程顺序执行与游戏主线程解耦多队列设计1 条图形队列 56 条计算队列7 条计算管线 × 8 队列对应 PS5 真实的 compute pipe 结构提交接口游戏通过 Submit() 提交图形与常量命令流通过SubmitCompute()提交计算任务通过SubmitFlipPreparation()预告翻页。每个提交被封装为Submission结构含Pm4Execution执行游标入队后由 GPU 线程逐个消费。三、PM4命令流解码CommandProcessor与跳转表PM4 是 AMD GPU 的命令打包格式PS5 的图形引擎就是靠它驱动硬件的。KytyPS5 中 PM4 的编码规则定义在 pm4.h类别说明典型指令控制指令IT_*绘制、同步、DMAIT_DRAW_INDEX_2、IT_WAIT_REG_MEM、IT_DISPATCH_DIRECT上下文寄存器CX_*视口、剪切、深度模板PA_CL_VPORT_XSCALE、DB_DEPTH_CONTROL着色器寄存器SH_*各阶段程序指针与资源SPI_SHADER_PGM_LO_PS、COMPUTE_PGM_LO用户配置寄存器UC_*图元类型、索引类型VGT_PRIMITIVE_TYPE、VGT_INDEX_TYPE解码核心是 CommandProcessorcommandProcessor.h。它的 Process() 方法按双字游标扫描 PM4 流支持间接缓冲区ProcessIndirectBuffer形成嵌套命令树遇到同步点可挂起Suspended等待。为了高效分派数百种操作码项目采用了跳转表机制见 pm4Dispatch.hg_cp_op_func命令操作、g_hw_ctx_func上下文寄存器、g_hw_sh_func着色器寄存器、g_hw_uc_func用户配置四张函数指针表按操作码索引直连处理函数例如CpOpDrawIndex→ DrawIndex()CpOpDispatchDirect→ DispatchDirect()CpOpWaitRegMem32→ WaitRegMem()CpOpFlip→ Flip()解码过程中积累的状态保存在三块寄存器上下文中HW::Context光栅化状态、HW::Shader各阶段着色器、HW::UserConfig图元配置定义于 hardwareContext.h。四、着色器重编译AGC指令 → IR → SPIR-VPM4 里保存的只是着色器程序的内存地址真正的机器码是 PS5 专属的 AGC 指令集无法直接喂给 Vulkan。KytyPS5 因此在 shader/recompiler/ 下实现了一条完整的着色器重编译器入口是 ShaderRecompiler.h 的TranslateProgramCompileProgram两步前端解码frontend/decode/ 将 AGC 双字指令解码为中间表示并构建 ShaderCFG 控制流图IR 优化ir/ 提供 SSA 重写、死代码消除、常量传播、资源跟踪与物化ResourceTracking / ResourceMaterialization等 pass把隐式的纹理/Sampler/UBO 资源显式化为可绑定的 descriptor后端发射backend/spirv/ 将 IR 逐指令发射为SPIR-V再由 PipelineCache 缓存为 Vulkan 管线避免重复编译。计算着色器光追光线发射、FSR 超分等都走计算管线与图形各阶段共用这套流程重编译正确性由 ShaderRecompilerComputeTests.cpp 等单测守护。五、Tile解压缩与内存页映射PS5 显存普遍使用tile 存储格式256B / 4KB / 64KB 分块直接读线性地址会拿到乱序像素。KytyPS5 的解法布局计算tile.h 定义TileBlockFamilyStandard256B、Standard4KB、Prt64KB、RenderTarget64KB 等家族TileGetTiledTextureLayout精确还原每个 mip 的偏移与大小GPU 解 tile宿主侧用一组 compute 着色器在线解压如 gpu_tiler_standard256.comp、gpu_tiler_standard64.comp调度逻辑在 tiler.h按需分页PageManager renderContext.h 的InvalidateMemory/HandleFault实现 guest 内存→显存页的惰性映射配合 VMA 分配器vma.cpp管理显存。六、Vulkan录制与提交解码出的 Draw/Dispatch 请求最终落到宿主侧 RenderContext它持有CommandSchedulerVulkan 命令缓冲录制与队列提交、DescriptorHeap描述符、各级缓存纹理/缓冲/Sampler/Pipeline。绘制参数换算在 renderDraw.h 的ResolveDrawOffsets等处完成图像转换缩放、格式转换走 blitHelper.cpp。每帧所有命令录制完毕后由 CommandScheduler 批量 submit 到 Vulkan 设备队列。七、终点FLIP命令与交换链上屏当 CommandProcessor 解到自定义的FLIP操作码R_FLIP说明本帧绘制完毕调用 Flip() 转入 videoOut.h 的 VideoOutDriver——它同时是 PS5 VideoOut 系统模块 API 的宿主实现SubmitFlipFromGpu()在 GPU 命令流末尾追加交换链提交保证帧内容写完才上屏PrepareFlip()/CompleteFlip()完成vkAcquireNextImage→ blit →vkQueuePresent的交换链流程swapchain.cpp同时向游戏回注 flip/vblank 事件驱动游戏的下一帧循环。至此一帧画面完成PM4 双字 → SPIR-V → Vulkan 命令 → 窗口像素的全链路闭环小结一图回顾完整链路阶段核心文件职责命令提交graphicsRun.hGPU 线程 图形/计算队列PM4 解码commandProcessor.h操作码跳转表、同步挂起寄存器上下文hardwareContext.hContext/Shader/UserConfig 状态着色器重编译ShaderRecompiler.hAGC → IR → SPIR-V内存与 tiletile.h、pageManager.h解 tile、分页映射Vulkan 录制renderContext.h命令缓冲、描述符、管线缓存上屏输出videoOut.hFLIP、交换链、vblank 事件想动手深挖建议从 commandProcessor.h 的Process()入口和 pm4.h 的操作码表读起——理解了这两处整条 KytyPS5 的 Vulkan 渲染模拟链路就清晰了 ✨【免费下载链接】KytyPS5PlayStation 5 emulator for Windows, Linux and MacOS项目地址: https://gitcode.com/gh_mirrors/ky/KytyPS5创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考