我正在尝试为 MacOS 编写一个简单的游戏循环。我在 GLFW、SDL 和 MacOS 游戏端口等库中找到的用于 DOOM、Quake、Handmade Hero的事件轮询nextEventMatchingMask
解决方案是使用API。我对事件轮询的延迟感兴趣:
t0 = mach_absolute_time();
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES];
t1 = mach_absolute_time();
latency=t1-t0
我运行的实验(源代码)包括打开一个 Cocoa MacOS 窗口和“随机”生成鼠标和键盘事件。我在此类实验中获得的前 1000 个事件的典型延迟数如下所示
# latency percentiles in milliseconds
: 0% 5% 10% 15% 20% 25% 30% 35%
: 0.033830 0.047655 0.060302 0.071263 0.073450 0.075871 0.079204 0.083330
: 40% 45% 50% 55% 60% 65% 70% 75%
: 0.093038 0.107813 0.134466 0.143095 0.180434 0.334789 0.448111 0.500118
: 80% 85% 90% 95% 100%
: 0.524535 0.583159 0.648065 0.719931 36.567810
请注意,前 25% 的延迟超过半毫秒。即使没有可用的事件(图表上的零),我们也可以获得超过一毫秒的延迟(参见第 600 个事件附近浮动的零)。更糟糕的是,这是我在 Macbook 没有太多工作时观察到的典型情况:只有一个终端和测试程序。当更多应用程序运行时,情况会变得更糟。
我想知道如果在 MacOS 应用程序中可用,是否有更有效的方法来获取下一个(鼠标/键盘)事件。我是否缺少使nextEventMatchingMask
通话更高效的技巧?
可以在此处找到运行此测试并生成类似上述图的源代码:https ://github.com/laurolins/cocoa_poll_events_latency
(更新)按照爸爸在评论中提出的想法,我在没有任何鼠标/键盘移动的情况下进行了测试。以下是延迟百分位数:
# latency without any keyboard/mouse event in milliseconds
: 0% 5% 10% 15% 20% 25%
: 0.04029500 0.07617675 0.07908070 0.08556100 0.10188940 0.12956500
: 30% 35% 40% 45% 50% 55%
: 0.13832200 0.14023150 0.14802140 0.15003550 0.15045250 0.15088950
: 60% 65% 70% 75% 80% 85%
: 0.15125000 0.15162535 0.15190300 0.15235550 0.15313200 0.15972645
: 90% 95% 100%
: 0.16802250 0.21194335 35.93352900
等待 0.15 毫秒以发现没有生成事件的想法感觉不对!
(更新 2)刚刚对在 ubuntu 上运行的gzdoomSDL_EventPoll
和MessagePump
调用进行计时,我得到的延迟分布看起来好多了:
# 0% 5% 10% 15% 20% 25% 30%
:0.00095100 0.00186075 0.00215500 0.00226400 0.00234180 0.00241500 0.00255900
: 35% 40% 45% 50% 55% 60% 65%
:0.00289495 0.00652280 0.00712510 0.00749900 0.00770290 0.00807660 0.00888870
: 70% 75% 80% 85% 90% 95% 100%
:0.00897200 0.00905000 0.00931060 0.01374225 0.01728800 0.03256290 0.23016000
而在 MacOS 上,gzdoom 还与nextEventMatchingMask
(数百微秒的延迟数)的缓慢作斗争。结论:在 MacOS 上获取下一个键盘/鼠标事件的速度不仅是我的测试代码。