☰
OptiScaler 贡献开发指南:预编译头(PCH)使用规范与构建效率优化实践
2026/10/2 1:58:17 网站建设 项目流程
  • 图形学
  • 游戏开发

【免费下载链接】OptiScaler

OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2+/XeSS/FSR2+ inputs, replaces native upscalers, enables FSR-FG/XeFG on non-FG titles. Supports Nukem mod for DLSSG-to-FSR3 FG.

项目地址:https://gitcode.com/GitHub_Trending/op/OptiScaler
点击查看免费下载

本篇技术指南聚焦 OptiScaler 开源项目对贡献者提出的预编译头(Precompiled Header,PCH)使用规范。OptiScaler 是一个跨 GPU 的上采样/帧生成桥接层(支持 DLSS2+/XeSS/FSR2+ 输入、替换原生上采样器、为非帧生成游戏启用 FSR-FG/XeFG 等功能),代码量横跨 DirectX 11/12、Vulkan 与大量第三方 SDK,构建链庞大。阅读本文后,你将理解该项目如何通过规范的 PCH 用法将构建速度提升 2 倍以上,掌握.cpp/.h文件的正确 include 顺序、pch.h的内容边界,以及如何在贡献代码时避免触发全量重编译。

为什么 OptiScaler 如此依赖 PCH

OptiScaler 的源码体量巨大:OptiScaler/目录下有近 200 个源文件,覆盖 hooks/、upscalers/、framegen/、shaders/ 等数十个模块,并且大量文件同时依赖 Windows SDK、Vulkan、DirectX 12、NVNGX、spdlog、FidelityFX 等重型头文件。

如果每个.cpp文件都各自重新解析这些头文件,编译器将重复处理数百万行代码,构建时间会急剧膨胀。项目因此启用了 MSVC 的预编译头机制:把稳定、少变的系统/第三方头文件一次性编译成.pch缓存,后续每个源文件直接复用。

从 CONTRIBUTING.md 的说明可以确认:正确使用 PCH 能让 OptiScaler 的构建速度快于标准构建 2 倍以上;反之,一旦在头文件中包含pch.h、或把pch.h当作通用工具桶,就会破坏编译器缓存预编译状态的能力,被迫进行不必要的全量重编译,导致整体构建退化。

四条 PCH 硬性规范(贡献者必读)

所有向 OptiScaler 提交代码的贡献者都必须遵守以下要求(原文见 CONTRIBUTING.md):

  1. .cpp源文件:每个源文件必须把#include "pch.h"作为第一个非注释行。这是让编译器命中 PCH 缓存的前提,任何在它之前插入其他头文件或宏定义都会使该文件的 PCH 失效。
  2. .h头文件:严禁在头文件内部#include "pch.h"。头文件可能被多个.cpp间接包含,一旦其中出现 PCH include,会导致重复/错误的预编译状态引用,破坏整个缓存链。
  3. 工具代码边界:不要把通用工具函数、宏或全局声明塞进pch.h。这类代码应放入SysUtils.h,或新建一个职责明确的功能头文件。
  4. 依赖准入:只把大型、稳定的第三方或系统头文件(例如 Windows/SDK 头文件)加入pch.h。频繁变动、自己项目内部的头文件不应进入 PCH。

规范在源码中的落实

规范的第一条在仓库中得到了一致执行。搜索结果(#include "pch.h"计数)显示,从 dllmain.cpp 到 D3D12_Hooks.cpp、FSR2Feature_Dx12.cpp、Shader_Common.cpp、Nvngx_Nukems.cpp 等120 多个.cpp文件的第一行都是#include "pch.h",无一例外:

// dllmain.cpp 开头 #include "pch.h" #include "dllmain.h" // ...

而头文件侧则严格遵循规范第二条——搜索整个OptiScaler/目录,pch.h从不出现在任何.h文件中。

走进pch.h:内容边界的真实写照

OptiScaler/pch.h的完整内容很好地示范了规范第三条与第四条的落地方式(文件顶部注释即写明了三条铁律):

#pragma once // pch.h: This is a precompiled header. // - DO NOT include this file in other header files (.h/.hpp). // - This file must be the FIRST include in every implementation file (.cpp). // - Only include stable, rarely-changed system/third-party headers here // (e.g., Windows.h, Vulkan, DX12) to improve build speeds. #include "SysUtils.h" #include "Config.h"

注意一个容易误解的细节:pch.h内部确实#include "SysUtils.h"和"Config.h"——它们并非违反"只放稳定第三方头"的规则,而是因为SysUtils.h本身就是一堆稳定系统头文件的聚合层(见下文),Config.h是项目构建时的基础配置头;这两个头文件自身不再引入大量变动内容。这恰恰说明了第四条的意图:PCH 应容纳"几乎不变"的内容,而不是随业务迭代频繁改动的模块头。

pch.cpp:PCH 的“创建者”角色

OptiScaler/pch.cpp是整个 PCH 机制的起点,它只有一行:

#include "pch.h"

在 MSVC 工程中,只有一个编译单元被配置为PrecompiledHeader = Create(即生成.pch缓存文件),其他所有.cpp都被配置为Use(复用该缓存)。在 OptiScaler.vcxproj 中可以看到pch.cpp在 Debug / ReleaseDebug / Release 三个配置下均为Create:

<ClCompile Include="pch.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseDebug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> </ClCompile>

而其余所有源文件(以 Debug|x64 为例)均使用:

<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>

同时工程开启了MultiProcessorCompilation(多处理器并行编译)与stdcpplatest语言标准。可以推断:PCH + 多核并行编译的组合,是 OptiScaler 维持数百文件、多 SDK 依赖下可接受迭代速度的关键工程手段。

为什么工具代码要放进SysUtils.h而不是pch.h

规范第三条并非洁癖,而是有实际编译性能代价的:pch.h的任何改动都会让整个项目触发全量重建。如果开发者把随手写的工具宏、调试辅助函数塞进pch.h,那么每次调整这些工具代码,所有.cpp文件都会被强制重编译——这正是原文档警告的"全局工具桶破坏缓存"。

观察 SysUtils.h,这个被pch.h引用的头文件才是真正的"稳定系统头聚合层":

#pragma once #define WIN32_LEAN_AND_MEAN #define NOMINMAX #define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE #include <Windows.h> #include <string> #include <stdint.h> #include <libloaderapi.h> #include <ranges> #include <winternl.h> #include <d3dkmthk.h> #define NV_WINDOWS #define NVSDK_NGX #define NGX_ENABLE_DEPRECATED_GET_PARAMETERS #define NGX_ENABLE_DEPRECATED_SHUTDOWN #include <nvsdk_ngx.h> #include <nvsdk_ngx_defs.h> #define SPDLOG_USE_STD_FORMAT #define SPDLOG_WCHAR_FILENAMES #define SPDLOG_WCHAR_TO_UTF8_SUPPORT #include "spdlog/spdlog.h"

它集中了Windows.h、nvsdk_ngx.h(DLSS SDK)、spdlog等重型且少变的头文件,以及一系列项目级编译开关(如ENABLE_DEBUG_LAYER_DX12、VULKAN_DEBUG_LAYER、LOG_ASYNC等,默认注释关闭)。

而真正会经常变动的通用工具则放在 SysUtils.h 的后半部分——例如LOG_TRACE/LOG_DEBUG/LOG_INFO/LOG_WARN/LOG_ERROR等日志宏、SAFE_RELEASE/SAFE_CLOSE_HANDLE等资源释放宏、wstring_to_string/string_to_wstring/to_lower_in_place等字符串转换函数。由于 OptiScaler 同时面向 Windows 原生与 Linux 桥接场景(如 setup_linux.sh 所示),这些宽窄字符串转换工具是各模块的公共依赖。

这里存在一个值得说明的工程权衡:SysUtils.h本身也被pch.h包含,因此它里面的内容同样"进入"了 PCH。但因为它同时被其他头文件直接引用(属于项目基础设施),且改动频率极低,所以这种安排符合第四条"稳定优先"的原则;而新增业务工具函数的正确位置是另建功能头文件(如 Util.h、MathUtils.h),不要往pch.h里堆。

常见错误自查清单

贡献者提交代码前,可对照以下清单自检:

检查项正确做法错误示例(会导致构建退化)
.cpp首行#include "pch.h"必须是第一个非注释行先写#include <Windows.h>或业务头再包含pch.h
.h文件绝不包含pch.h在某.h里写#include "pch.h"
工具代码归属放入 SysUtils.h 或新建功能头把新宏/工具函数写进pch.h
新增大型依赖评估是否稳定、是否被多数文件需要把频繁改动的内部模块头塞进pch.h

额外提醒:由于 OptiScaler 同时维护 Debug / ReleaseDebug / Release / Win32 / x64 多套配置(见 OptiScaler.vcxproj 中的ItemDefinitionGroup),且工程通过DelayLoadDLLs延迟加载vulkan-1.dll、d3d12.dll等运行时库,提交时无需、也不应在这些生成配置上手工改动 PCH 相关节点。

小结

PCH 是 OptiScaler 控制庞大构建链的核心工程手段:pch.cpp负责Create缓存,120+ 个.cpp文件统一Use并强制首行包含pch.h,头文件永不触碰pch.h,通用工具与稳定系统头各归其位。贡献者只要守住这四条规则,就能让整个项目的构建保持比标准构建快 2 倍以上的速度,避免因个人代码风格触发全量重编译。构建相关的工程配置细节可继续查阅 OptiScaler.vcxproj 与 OptiScaler.vcxproj.filters,环境搭建步骤见 setup_windows.bat 与 setup_linux.sh。

  • 图形学
  • 游戏开发

【免费下载链接】OptiScaler

OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2+/XeSS/FSR2+ inputs, replaces native upscalers, enables FSR-FG/XeFG on non-FG titles. Supports Nukem mod for DLSSG-to-FSR3 FG.

项目地址:https://gitcode.com/GitHub_Trending/op/OptiScaler
点击查看免费下载

相关推荐

上一篇:代码优化技巧:Interview_DS_Algo中的性能调优实战
下一篇:WebRTC-Experiment 文本聊天实战:用 DataConnection.js 实现 DataChannel 文本与文件分享

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

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

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

立即咨询