介绍
Ixeris
概述
Ixeris 是一个通过优化事件轮询来提升客户端性能的模组。
你可能注意到,移动鼠标时 FPS 会明显下降。部分 FPS 降低是因为转动视角时,游戏需要执行额外任务,例如计算区块的可见性。然而,由于原生事件轮询代码效率低下,以及 JNI 向上调用的开销,一些原本可以用于渲染的 CPU 时间被不必要地消耗在了事件轮询上。在 Windows 上,这一问题尤为明显,尤其是当鼠标轮询率较高时。
Ixeris 主要通过以下两项措施解决这一问题:
- 线程化事件轮询。Ixeris 不再在同一线程中同时执行渲染和事件轮询,而是在主线程上执行事件轮询,并将渲染交由单独的渲染线程处理。
- 缓冲原始输入(仅限 Windows)。将输入轮询方式从效率较低的
GetRawInputData(每个输入事件调用一次)切换为GetRawInputBuffer,后者允许批量读取原始输入消息(所有事件只需调用一次)。此外,将这项工作放在 Java 代码中执行,还消除了 JNI 向上调用的开销。
基准测试
这些测试均在世界完全加载且帧率稳定后进行。
测试 1:游戏内
此测试比较鼠标被捕获时的性能,即光标不可见时的性能。测试在没有实体的超平坦世界中进行。
此测试在 Windows 上进行,Ixeris 默认使用缓冲原始输入来提升性能。“Ixeris,未缓冲”列显示禁用该选项时的 FPS。
| 轮询率 | 未使用 Ixeris | Ixeris,未缓冲 | Ixeris,已缓冲 |
|————–|—————-|———————-|——————|
| 8000 Hz | 12 FPS | 83 FPS(6.9 倍) | 121 FPS(10.1 倍) |
| 2000 Hz | 76 FPS | 114 FPS(1.50 倍) | 135 FPS(1.78 倍) |
| 500 Hz | 134 FPS | 145 FPS(1.08 倍) | 151 FPS(1.13 倍) |
测试 2:菜单中
此测试比较鼠标未被捕获时的性能,即光标可见时的性能,例如 F3+Esc 暂停界面。在这种情况下,游戏不会使用原始输入,因为游戏需要知道实际的光标位置,而不是原始相对移动量。轮询率为 1000Hz。
“空闲 FPS”列显示鼠标未移动时的 FPS,后两列则显示在游戏窗口上快速移动鼠标时的 FPS,分别对应未使用 Ixeris 和使用 Ixeris 的情况。请注意,此测试是在 Ixeris 首次发布时进行的,此后已经进行了许多改进。
| | 空闲 FPS | 未使用 Ixeris | 使用 Ixeris |
|—————–|———-|—————-|—————–|
| Windows | 233 FPS | 133 FPS | 165 FPS(1.24 倍) |
| Linux(X11) | 358 FPS | 320 FPS | 355 FPS(1.11 倍) |
| Linux(Wayland) | 364 FPS | 289 FPS | 298 FPS(1.03 倍) |
技术细节
线程安全
在当前状态下,Ixeris 不应破坏线程安全性。使用 “glfwSet*Callback“ 注册的回调会在线程中执行。必须在主线程上调用的 GLFW 函数,如果从其他线程调用,则会被调度到主线程。这些调用如果可以安全地延迟,可能会立即返回;否则可能会阻塞调用方,直到调用完成。
从 3.1.0 版本开始,GLFW 文档中的线程安全要求已得到严格遵守。
GLFW 状态缓存
大多数 GLFW 函数都必须从主线程调用。不过,许多模组可能会从渲染线程调用这些函数。为了避免线程通信带来的性能下降,Ixeris 会缓存常用的 GLFW 状态,以便从任意线程快速访问,而无需将调用转发到主线程。这些缓存是安全的,不会引入额外延迟。
增强型 FPS 限制器
原版 FPS 限制器(26.1 之前)存在缺陷,它使用 glfwWaitEventsTimeout 进行休眠。然而,此函数无法从渲染线程调用,因此与 Ixeris 配合时无法发挥最佳效果。
Ixeris 以混合方式重写了 FPS 限制器:进行精确休眠,并在等待时间非常短时开始自旋等待。
术语表
- 主线程是启动游戏时所在的线程。大多数 GLFW 函数都必须在此线程上调用,并且该线程负责轮询事件。
- 渲染线程负责执行游戏通常会执行的所有操作,但不包括事件轮询。
在原版 Minecraft 中,这两个术语是同义的。
评论
登录后评论和评分