GitHub 今日推荐|SCSKiller:游戏着色器预编译消除卡顿

GitHub 今日推荐|SCSKiller:游戏着色器预编译消除卡顿

一句话看懂

项目地址:github.com/BlueHeisenb...

SCSKiller 在游戏未运行时预编译着色器并写入显卡驱动缓存,游戏启动后直接读取编译结果,避免首次遇到新效果时因即时编译导致的画面卡顿。仅支持 Windows 10 (version 2004) 或 11 的 64 位系统,支持 NVIDIA 和 AMD 显卡的 DirectX 12 游戏,NVIDIA 还支持 DirectX 11 游戏。

它解决什么问题

游戏遇到新效果时 GPU 驱动必须即时编译着色器(shader),这段编译过程会导致画面卡顿,称为"shader compilation stutter"(着色器编译卡顿)。传统解决方案是游戏自带 PSO 缓存,但玩家首次游玩时仍需边玩边编译,无法消除卡顿。手动游玩预热需完整体验所有效果才能触发所有着色器编译,耗时且难以覆盖所有组合。Final Fantasy VII Rebirth 在 RTX 5090 上测量显示,未预编译时有 19 次卡顿,最坏延迟 76ms;预编译后卡顿次数降至 0,最坏延迟降至 5ms。驱动更新会清空着色器缓存,需重新编译所有游戏。

核心概念速览

Driver shader cache(驱动着色器缓存):显卡驱动存储已编译着色器的缓存。NVIDIA 按 exe 文件名键控其 DirectX 12 缓存,文件夹路径、文件内容和 DirectX 12 运行时版本不影响键值。本项目通过同名进程预填充此缓存,游戏启动后直接读取。

PSO (Pipeline State Object)(管线状态对象):图形管线状态对象,包含着色器阶段组合。一个游戏可能创建数千个 PSO,每个对应不同效果。本项目推算游戏可能创建的所有 PSO 并预编译,覆盖率高于手动游玩。

AGS registration(AGS 注册):AMD 显卡服务注册。AMD 按应用名键控缓存,需通过 AGS (AMD GPU Services) 以游戏身份注册设备,才能将编译结果写入游戏对应的缓存位置。

Agility SDK(敏捷 SDK):DirectX 12 的可更新运行时。当游戏使用特定版本 SDK 时,编译进程需使用相同版本以保证管线对象二进制兼容,否则驱动缓存无法被游戏识别。

架构拆解

项目分为 C# 图形界面层和 C++ 编译执行层。App 展示游戏库和编译队列,调用 Planner 生成编译计划。Planner 通过 EngineReaders 读取各游戏引擎(Unreal、Unity、FromSoft 等)的着色器文件,推算 PSO 组合,生成 scskiller_gen.db。Warmer 启动 scskiller_warm.exe 子进程执行实际编译。scskiller_warm 是 C++ 编写的编译执行器,以游戏同名进程身份创建 D3D12 设备和 PSO,驱动将编译结果写入缓存。GpuBackends 检测显卡供应商并提供对应的缓存管理接口,NvidiaBackend 和 AmdBackend 实现供应商特定的缓存管理。

关键实现走读

规划器版本管理与缓存策略

csharp 复制代码
public sealed class Planner(string? packDir = null, string? sharedPackDir = null) : IPlanner
{
    public MiddlewarePacks? Packs { get; } = packDir == null ? null : new MiddlewarePacks(packDir);
    public MiddlewarePacks? SharedPacks { get; } = sharedPackDir == null ? null : new MiddlewarePacks(sharedPackDir);

    public const int Version = 31;

    internal static bool D3D11Cache(VendorCaps caps) => caps.Profile == "nvidia-1";

    internal static bool RtCollectionCache(VendorCaps caps) => caps.RtCacheGranularity == RtCacheGranularity.Collection;

    internal static bool IsD3D11(ShaderInfo s) => s.Stage <= Stage.Compute && s.ShaderModel[^3..] is "4_0" or "4_1" or "5_0";

    public const string NoRecording = "no recording needed";
    public const string Untested = UntestedNote + ": playing with recording on improves it";

做了什么: Planner 类管理着色器包目录和共享包目录,定义版本号 31,实现三个静态判断方法:D3D11Cache 检查供应商是否支持 DirectX 11 缓存(仅 NVIDIA),RtCollectionCache 检查光线追踪缓存粒度,IsD3D11 根据着色器阶段和模型版本判断是否为 DirectX 11 着色器。

为什么这样写: 版本号用于标记编译计划格式变更,不兼容时需重新生成。D3D11Cache 判断避免在 AMD 显卡上尝试不支持的 DirectX 11 预编译。RtCollectionCache 判断影响光线追踪管线的编译策略,部分供应商需按集合粒度编译。IsD3D11 区分 DirectX 11 和 12 着色器,前者需通过 warm11.cpp 的 D3D11 设备单独处理。

没有它会怎样: 无版本管理会导致旧编译计划与新代码不兼容。无供应商判断会在 AMD 显卡上浪费时间尝试 DirectX 11 编译。无着色器模型判断会将 DirectX 11 着色器错误地提交给 D3D12 设备。

编译执行器的缓存键控机制

cpp 复制代码
// scskiller_warm: fill a game's driver shader cache from outside the game, no injection.
// NVIDIA keys its D3D12 cache on the exe *file name* (measured: folder, file contents and D3D12 runtime version don't
// matter), so a copy of this exe named like the game, replaying the game's scskiller.db + scskiller_gen.db, warms it.
// Its D3D11 cache is keyed the same way: the gen db's D3D11 items are drawn once each on a D3D11 device (warm11.cpp).
//
//   scskiller_warm <workdir> <game exe file name> [--threads N] [--priority below|idle] [--start N]
//                  [--stop-event <name>] [--adapter-luid <hex>] [--rt-threads N] [--skip i,j,...]
//                  [--memory-mb N] [--package <app user model id>] [--stage-path <install folder>\<dir>\<exe>]
//                  [--skip-keys <sha1 hex>,...] [--isolate i,j,...]
//                  [--ags <amd_ags_x64.dll> --ags-app <name> --ags-engine <name>] [--pass K] [--layer <folder>]
//                  [--d3d12 <the game's Agility SDK folder>]

做了什么: scskiller_warm.exe 被重命名为游戏同名,接受工作目录和游戏 exe 文件名作为必需参数。支持线程数、优先级、起始位置、停止事件、适配器 LUID、光线追踪线程数、跳过项、内存限制、UWP 包名、安装路径、跳过键、隔离项、AGS 参数、编译遍数、层文件夹、Agility SDK 路径等可选参数。

为什么这样写: NVIDIA 按 exe 文件名键控 DirectX 12 缓存,与文件夹路径、文件内容和 DirectX 12 运行时版本无关。重命名为游戏同名使驱动将编译结果写入游戏对应的缓存位置。AMD 需通过 AGS 参数以游戏应用名和引擎名注册设备。Agility SDK 参数确保编译环境与游戏运行时一致。线程数和优先级参数平衡编译速度与系统占用。跳过和隔离参数处理崩溃或内存问题的特定 PSO。

没有它会怎样: 不重命名会将编译结果写入 scskiller_warm 自身的缓存,游戏无法读取。不传递 AGS 参数会导致 AMD 显卡无法识别游戏身份。不传递 Agility SDK 路径会使用系统默认版本,与游戏运行时不一致时缓存失效。无线程和优先级控制会在编译时冻结系统。无跳过参数会在遇到问题 PSO 时中断整个编译流程。

动手上手

从 GitHub Releases 页面下载 SCSKiller-Setup.exe 并运行安装。

启动 SCSKiller 后自动扫描 Steam、Epic、EA、GOG、育碧等十个游戏平台的已安装游戏。

点击"Add all recommended"将推荐游戏添加到编译队列,或手动选择需要预编译的游戏。

确保游戏关闭状态,点击"Compile"按钮开始编译。界面显示每个游戏的着色器数量、缓存大小、编译时间及状态。

编译完成后从游戏平台启动游戏,或使用 SCSKiller 中的"Play"按钮通过游戏平台启动。

可验证结果: 游戏启动后首次进入场景和遇到新效果时,画面流畅无卡顿。对比未预编译的游戏,可明显感受到减少的帧冻结次数和降低的最坏帧时间。

对于提示需要录制的游戏,打开"Record"开关,游玩约五分钟触发尽可能多的效果,关闭游戏后执行"Compile"。录制器会向游戏文件夹添加 d3d12.dll 等文件,关闭录制后自动移除。

应用场景

新游戏首次启动: 游戏关闭时打开 SCSKiller,添加该游戏到队列并点击 Compile,完成后启动游戏。

驱动更新后重新预热: SCSKiller 检测到驱动版本变化会自动标记需重编译的游戏,重新执行编译流程。驱动更新清空着色器缓存,需重新编译所有游戏。

录制未知管线的游戏: 对提示需要录制的游戏,打开 Record 开关,游玩约五分钟,关闭游戏后执行 Compile。录制器会向游戏文件夹添加 d3d12.dll 等文件,关闭录制后自动移除。部分管线无法从文件推断,需要录制游玩过程捕获实际创建的 PSO。

独立分析

项目在 README FAQ 中明确说明"SCSKiller never launches them, injects into them or gives them the recorder. It only reads their files",证明其对反作弊游戏是安全的。NVIDIA 和 AMD 的 DirectX 12 缓存按 exe 文件名键控,warm.cpp 注释和 README Results 测量数据证明有效性。与游戏自带的 PSO 缓存相比,游戏自带缓存需首次游玩时边玩边编译,仍有卡顿;本工具提前编译进驱动缓存,游戏直接读取。与手动游玩预热相比,手动需完整体验所有效果才能触发所有着色器编译;本工具通过文件推算覆盖所有可能组合,效率和覆盖率更高。

项目采用 GPL-3.0-or-later 许可证,官方下载仅限 GitHub Releases 页面,非官方渠道可能存在风险。未签名发布包会触发 Windows SmartScreen 警告,但不影响功能。构建需要 Visual Studio 2022 和 .NET 10 SDK。

局限与风险

仅支持 Windows 系统,不支持 Linux 或 macOS。Intel 显卡尚未支持,作者说明"I don't have one to test on"。

部分管线无法从文件推断,需要录制游玩过程。录制功能不适用于反作弊游戏,ELDEN RING 等例外需用户自担风险。

无法修复非着色器编译导致的卡顿,如遍历和流送卡顿(traversal and streaming stutter),这些卡顿源于资源加载而非着色器编译。

未签名发布包会触发 Windows SmartScreen 警告,需用户确认信任后运行。

驱动更新会清空着色器缓存,需重新编译所有游戏,维护成本随游戏数量增加。

结论卡片

适用人群: Windows PC 高帧率游戏玩家,大型光影效果游戏用户,对显卡驱动缓存管理有需求的技术爱好者。对 NVIDIA/AMD DirectX 12 游戏有显著效果,需要驱动更新后重新编译。

不适用人群: 非 Windows 用户,Intel 显卡用户,严格反作弊游戏玩家,需要签名软件的环境。

关注理由: 项目通过预编译着色器消除游戏运行时卡顿,测量数据显示最坏延迟可降低 90% 以上。支持自动检测十个游戏平台,提供录制器处理未知管线。开源 GPL-3.0-or-later 许可证,社区可审计代码安全性。


项目地址:github.com/BlueHeisenb...

相关推荐
JavaPub-rodert1 小时前
Docker 镜像地址总失效?基于 DockerHub 项目用 GitHub Actions 做一个自动检测状态页
docker·容器·github
miofly2 小时前
GitHub 日榜趋势速报 | 2026-10-06
开源·github
ccstuck2 小时前
AI安全系列:开源RAG系统测试
人工智能·安全·开源·ai安全
1024奇点3 小时前
【仓颉语言入门 · 第26课】
开发语言·ide·开源
liangsheng_g3 小时前
SpringAOP两套代理创建路线设计哲学与开源实践
spring·开源·代码规范
海绵宝宝转agent14 小时前
MySql高频面试八股开源笔记总结
mysql·面试·开源
周杰伦fans15 小时前
8GB显存下模型量化实战指南
人工智能·后端·c#
samble17 小时前
从零搭建灌装监控系统(十二):配置系统,原子写入与容错
c#·wpf·mvvm·modbus·工业控制
ianzh17 小时前
workbuddy-to-dsh使用教程
github