UE4输入延迟
Render线程
① InitViews,也就是剔除,排序,合批,筛选出现在视口看得见的DrawCommand
② RHICommands Generation,也就是后面一大坨Pass的部分(PrePass,BasePass,PrelightComposition,LightPass,TransparentPass,PostProcess,UI)
把DrawCommand提交给RHI线程。(注意这里RHI线程处理完上一帧的DrawCommand,才可以提交当前帧的DrawCommand)
注:①和②之间的Stall就是在等RHI线程处理完上一帧的DrawCommand
RHI线程、GPU
③ DrawCommand to GPU Command,把DrawCommand转化为渲染API后端(dx,vk,ogl,metal)的GPU Command;然后GPU Command submit,提交DrawCall
④ 收到RHI源源不断提交过来的GPU Command,GPU会并行开始执行,并将渲染结果绘制到BackBuffer中
⑤ 若VSync来临前,BackBuffer已渲染完毕,RHI线程在执行Swap chain flip(调用SwapBuffer或Present函数),就会立即将BackBuffer交换到SF的CompositonBuffer(合成缓冲区) 注:③和⑤之间的RHI线程Stall,就是在等这个VSync信号
若VSync来临前,BackBuffer没有渲染完毕,RHI线程在执行Swap chain flip(调用SwapBuffer或Present函数)就会阻塞等待,在后续的VSync信号来临时,再检查BackBuffer是否渲染完毕,直到BackBuffer完成并将其交换到CompositonBuffer(合成缓冲区)
SF(SurfaceFlinger)合成
也称硬件合成器,Hardware Composer
SurfaceFlinger 会组合出屏幕应该最终显示出的内容,并提交到Display显示器
⑥ Compositon Buffer(合成缓冲区)
Display显示器
⑦ 将FrontBuffer画面显示在Display上(最终看到的画面)
相关控制台变量
r.vsync
r.vsync 1 // 开启垂直同步
r.vsync 0 // 关闭垂直同步
r.VSyncEditor
r.VSyncEditor 1 // 用于编辑器PIE下开启垂直同步
r.VSyncEditor 0 // 用于编辑器PIE下关闭垂直同步
r.OneFrameThreadLag
r.OneFrameThreadLag 1 // 为1时启用(缺省),为0时关闭
可确保游戏线程不会比渲染线程提前一整帧以上。
rhi.SyncInterval
设置VSync同步的频率
rhi.SyncInterval 0 // 不锁同步频率
rhi.SyncInterval 1 // VSync同步频率设置为60Hz (16.66ms)
rhi.SyncInterval 2 // VSync同步频率设置为30Hz (33.33ms)
rhi.SyncInterval 3 // VSync同步频率设置为20Hz (50.00ms)
r.GTSyncType
r.GTSyncType 0 // 游戏线程与渲染线程同步(缺省)
r.GTSyncType 1 // 游戏线程与RHI线程同步(相当于并行渲染前的UE4)
r.GTSyncType 2 // 游戏线程与GPU swap chain flip同步 (仅在支持的os平台上)
为实现模式2的同步,引擎通过调用SwapBuffer或Present函数时传入驱动程序的索引来跟踪显示的帧。此索引是从平台帧翻转统计数据检索的,它指示每帧翻转的精确时间。
引擎用户使用这些值来预测下一帧应于何时翻转,然后基于该时间启动下一个游戏线程帧。
r.GTSyncType 2也适用于更新率为60Hz的游戏(即:rhi.SyncInterval 设置为1),但是采用此设置的好处不易察觉,由于与30Hz相比,帧率为两倍,输入延迟会降低一半。
注:在不支持的os平台上,r.GTSyncType 2 将会退回到模式1。
rhi.SyncSlackMS
决定应用到预测的下一次垂直同步时间的偏移。减小该值将缩小输入延迟,但是会缩短引擎管道,更容易出现由卡顿造成的掉帧。而增大该值会延长引擎管道,赋予游戏更多应对卡顿的弹性,但是会增大输入延迟。
一般来说,使用这个新的帧同步系统的游戏应在维持可接受帧率的情况下尽可能缩小rhi.SyncSlackMS。
通过组合这些CVar变量,修改游戏线程、渲染线程及RHI线程和GPU之间线程同步的执行方式,来平衡输入延迟和卡顿。
CVar组合1
最大输入延迟为66 ms ≈ 33.33 ms * 2(两个30Hz帧):
r.Vsync 1 // 开启垂直同步 rhi.SyncInterval 2 // VSync同步频率设置为30Hz (33.33ms) r.GTSyncType 2 // 游戏线程与GPU swap chain flip同步 (仅在支持的os平台上) 注:GPU等VSync垂直同步,将BackBuffer交换到FrontBuffer进行显示,延迟1帧 r.OneFrameThreadLag 1 // 游戏线程比渲染线程最多快1帧 注:Render线程最多比Game线程延迟1帧 rhi.SyncSlackMS 0 // 不延迟垂直同步 注:如果将 rhi.SyncSlackMS 增大至10,则最佳输入延迟为76ms。
CVar组合2(示意图为这种情况)
最大输入延迟为66 ms ≈ 16.66 ms * 4(四个60Hz帧):
r.Vsync 1 // 开启垂直同步 rhi.SyncInterval 1 // VSync同步频率设置为60Hz (16.66 ms) r.GTSyncType 0 // 游戏线程与渲染线程同步 注1:RHI线程比Render线程延迟1帧 注2:RHI等GPU,写BackBuffer,延迟1帧 注3:GPU等VSync垂直同步,将BackBuffer交换到FrontBuffer进行显示,延迟1帧 r.OneFrameThreadLag 1 // 游戏线程比渲染线程最多快1帧 注:Render线程最多比Game线程延迟1帧 rhi.SyncSlackMS 0 // 不延迟垂直同步 注:如果将 rhi.SyncSlackMS 增大至10,则最佳输入延迟为76ms。
其他控制台变量
变量 | 含义 |
rhi.SyncAllowEarlyKick | When 1, allows the RHI vsync thread to kick off the next frame early if we've missed the vsync. |
RHI.SyncThreshold | Number of consecutive 'fast' frames before vsync is enabled. |
RHI.SyncWithDWM | If true, synchronize with the desktop window manager for vblank. |
参考
UE4のスレッドの流れと Input Latency改善の仕組み
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)