他正在跑一个渲染性能测试,场景里有三百多个动态光源,帧率掉到了二十以下。正常情况下,这个数量级的光源不应该造成这么大的性能损耗。他打开性能分析器,看到多光源阴影合并的模块占用了百分之四十的GPU时间。这个模块是他自己写的,每一行代码都记得。问题不出在算法本身,出在架构层面。阴影贴图的生成和合并是串行执行的,每个光源都要等前一个处理完才能开始。
他在笔记本上画了一张新的流程图。把串行改成并行,每个光源的阴影贴图独立生成,最后统一合并。理论上有机会把性能提升一倍以上。但这个改动涉及到底层渲染管线的重构,不是修修补补能解决的。他把笔记本合上,走到林子轩工位前。
林子轩正在调试《共火》的网络同步模块,屏幕上全是密密麻麻的时间戳日志。沈连河把笔记本翻开,指着那张流程图。林子轩看了大概十秒,把棒棒糖从左边挪到右边。
“要动管线。”
“对。”
“多久。”
“两周。如果每天工作十四小时。”
林子轩没再问。他转回去继续看日志,但沈连河注意到他把手机倒扣在桌上,意思是别打扰。这不是拒绝,是在清空日程。
接下来的两周,沈连河几乎睡在了办公室。他在角落里搭了一个行军床,是许知意从网上买的,绿色帆布面,铁管支架,躺上去吱吱响。每天凌晨两三点,他会在行军床上躺四五个小时,然后爬起来继续写代码。许知意每天早上一到办公室,第一件事就是去看行军床上有没有人。如果有,她就轻手轻脚走过去,把毯子往上拽一拽。
沈连河重写了多线程渲染管线的调度核心。原来是一个主线程负责所有渲染指令的提交,现在拆成了六个工作线程,每个线程独立处理一部分渲染任务,最后通过一个无锁队列合并结果。多光源阴影的并行生成只是第一步,他还顺手优化了粒子系统的批处理逻辑和骨骼动画的矩阵计算。
第十三天,他把代码合并到主分支,开始跑回归测试。前十二个小时,一切正常。第十三个小时,程序崩溃了。崩溃日志指向一个内存地址,追踪下去,发现是六个线程同时访问同一个资源时发生了竞争条件。他在那个资源访问的地方加了一个原子锁,重新编译,再跑。又跑了十个小时,没有崩溃。
他在笔记本上写了一行字。“零点六,完成。”然后躺上行军床,毯子都没盖就睡着了。
林子轩是在第十四天的凌晨开始测试新版渲染管线的。他把测试场景的光源数量从三百个增加到五百个,帧率从二十降到了十八,比原来三百个光源时的表现还好。他又加了一千个,帧率掉到了十二。这不是引擎的问题,是硬件本身的算力到顶了。集成显卡的填充率就那么高,软件优化救不了物理极限。
他在测试报告里写了一句话。“零点六渲染管线性能提升约百分之四十,多光源场景表现尤为显著。当前瓶颈已从软件转向硬件。”
孟缘看到这句的时候正在吃午饭。他把筷子放下,把那行字读了两遍。转向硬件。他在心里默念了这四个字,然后把饭吃完,没有跟任何人提起。
零点六版本上线后的第一周,顾林来了。
顾林是深海科技大学的副教授,四十二岁,异构计算和渲染管线方向的专家。他和孟缘的相识始于一次讲座,孟缘回学校招人时在走廊上听了他二十分钟的课,讲座结束后聊了将近一小时。那次聊天让顾林对橘猫的九命引擎产生了兴趣。一个初创团队能在没有硬件厂商支持的情况下写出这样的渲染架构,在他眼里比任何商业计划书都有说服力。
顾林到办公室的时候,沈连河正趴在桌上睡觉。行军床还没收,毯子搭在椅背上。许知意想叫醒他,顾林摆了摆手。
“让他睡。我看代码就行。”
他在沈连河的工位前坐下,打开引擎的源代码仓库,从渲染管线的入口函数开始看。看了大概四十分钟,中间没有喝水,没有上厕所,没有跟任何人说话。林子轩路过的时候停了一下,看到顾林正在翻自己写的那段并行调度代码,没打扰,去倒了一杯水放在他旁边。
四十分钟后,顾林合上笔记本,站起来,找到孟缘。
“你们的渲染架构写得很好。比我见过的很多商业引擎都要干净。”他说这话的时候表情很认真,不像在客套,“但有一个问题。你们在用软件的思维做图形计算。所有东西都在CPU上调度,GPU只负责执行最终的绘制指令。这个模式在当前的硬件条件下没问题,但如果有一天你们想跑硬件加速,比如光线追踪或者大规模粒子模拟,整个架构要全部重写。”
孟缘靠在椅背上。“你的意思是,我们现在写的代码,以后可能都要扔掉。”
“不是扔掉,是重构。现在的架构是把GPU当作一个被动的绘制设备,所有智能都在