一直以来我们玩iw游戏,或者各种gamemaker制作的游戏的时候都会遇到一个问题:变速,对于我来说还有输入延迟问题。这个问题困扰了很多人。后来有人弄了一个叫做DBGHELP.dll的文件还有一个叫作melatonin的软件。那么这两个东西是如何修复这些问题的呢?本篇文章就是来探讨这个的。
我们先来看看DBGHELP上的github页面是怎么解释的:

简单地说,DBGHELP是一个假的dll,它的作用是把thread scheduler resolution这个东西设置为1毫秒。那么那又是个什么东西呢?
简单地说,每个windows应用都会休眠。比如我们在玩iwanna的时候,因为iwanna只有50fps,所以只要每20毫秒内更新一次游戏就没问题。但是我们的cpu远不止这点能力。为了减少耗电量之类的原因,在游戏做好下一次更新的计算后,游戏就会休眠一段时间。thread scheduler resolution的作用就是每隔多久检查一下这些休眠的应用,好让他们醒过来。一般来说,这个时间段是大约15毫秒左右。
但是问题就来了。假如我们想让游戏休息1毫秒。在gamemaker的应用里,它们会使用Sleep(时间)来休眠。但是Sleep的实际响应时间和括号里填写的时间不总是相同的。比如我们Sleep(1),程序实际上有可能会在这个指令后的1-15毫秒的任意一个时间段内醒过来。如果是一般应用那还好,但是如果是游戏的话,这就意味着游戏只要尝试休眠,就会有响应时间段不稳定的风险。
比如说cpu花了15毫秒完成下一次更新的计算,然后它尝试休息5毫秒。因为Windows每15毫秒才叫醒休眠的应用,等到下一次游戏醒来的时候,它很有可能就错过了该更新游戏信息的时候,从而导致帧数不稳定。
所以DBGHELP通过把叫醒应用的这个时间段改为1毫秒解决了这个问题。
那GMS有没有应对这个问题的方法呢,答案是有的。它就是sleep margin。我们再举一个例子。
假设cpu花了5毫秒完成计算,理论上游戏应该休息15毫秒。但是假如sleep margin为10,它会再运行5毫秒的空运算(就是什么都不干,但是仍然醒着),之后再睡眠。在这5毫秒内,如果游戏到了该更新的时候了,它就会准时更新。
由此可见,假如我们把sleep margin设置为大于20的话,因为iw只会每20毫秒更新一次,所以除去cpu计算花的时间,剩下的时间cpu也没有闲着,而是在运行空命令。这样游戏就可以准时地更新了。但是,因为cpu要经常运行空命令,所以耗电量和发热也会增加。

而如果游戏已经有了DBGHELP,就不用再设置成大于20了,那样的话就是浪费额外的cpu资源了。
事情到这里貌似还都能圆的上,然而melatonin的方法貌似是完全相反的。在你使用melatonin注入dll后,它提示的竟然是sleep margin set to 1!不过melatonin里面的那个DLL写的又和说的不一样,我认为可能set to 1要么是个笔误,要么就是melatonin其实使用了和DBGHELP一样的办法所以才会把sleep margin改为1。

在笔者的电脑上(Windows 10 version 21H2),把sleep margin设置为1或者不使用DBGHELP/melatonin游戏只有30左右fps;sleep margin大于20或使用上述办法时没有问题;sleep margin刚好为20时游戏偶尔会变速。
值得一提的是,一些人的电脑就算sleep margin为1也没有什么影响。
经过我的调查,貌似是某次Windows 10的更新(Windows 10 2004)后出现了这个问题。
我们先来看看DBGHELP上的github页面是怎么解释的:

简单地说,DBGHELP是一个假的dll,它的作用是把thread scheduler resolution这个东西设置为1毫秒。那么那又是个什么东西呢?
简单地说,每个windows应用都会休眠。比如我们在玩iwanna的时候,因为iwanna只有50fps,所以只要每20毫秒内更新一次游戏就没问题。但是我们的cpu远不止这点能力。为了减少耗电量之类的原因,在游戏做好下一次更新的计算后,游戏就会休眠一段时间。thread scheduler resolution的作用就是每隔多久检查一下这些休眠的应用,好让他们醒过来。一般来说,这个时间段是大约15毫秒左右。
但是问题就来了。假如我们想让游戏休息1毫秒。在gamemaker的应用里,它们会使用Sleep(时间)来休眠。但是Sleep的实际响应时间和括号里填写的时间不总是相同的。比如我们Sleep(1),程序实际上有可能会在这个指令后的1-15毫秒的任意一个时间段内醒过来。如果是一般应用那还好,但是如果是游戏的话,这就意味着游戏只要尝试休眠,就会有响应时间段不稳定的风险。
比如说cpu花了15毫秒完成下一次更新的计算,然后它尝试休息5毫秒。因为Windows每15毫秒才叫醒休眠的应用,等到下一次游戏醒来的时候,它很有可能就错过了该更新游戏信息的时候,从而导致帧数不稳定。
所以DBGHELP通过把叫醒应用的这个时间段改为1毫秒解决了这个问题。
那GMS有没有应对这个问题的方法呢,答案是有的。它就是sleep margin。我们再举一个例子。
假设cpu花了5毫秒完成计算,理论上游戏应该休息15毫秒。但是假如sleep margin为10,它会再运行5毫秒的空运算(就是什么都不干,但是仍然醒着),之后再睡眠。在这5毫秒内,如果游戏到了该更新的时候了,它就会准时更新。
由此可见,假如我们把sleep margin设置为大于20的话,因为iw只会每20毫秒更新一次,所以除去cpu计算花的时间,剩下的时间cpu也没有闲着,而是在运行空命令。这样游戏就可以准时地更新了。但是,因为cpu要经常运行空命令,所以耗电量和发热也会增加。

而如果游戏已经有了DBGHELP,就不用再设置成大于20了,那样的话就是浪费额外的cpu资源了。
事情到这里貌似还都能圆的上,然而melatonin的方法貌似是完全相反的。在你使用melatonin注入dll后,它提示的竟然是sleep margin set to 1!不过melatonin里面的那个DLL写的又和说的不一样,我认为可能set to 1要么是个笔误,要么就是melatonin其实使用了和DBGHELP一样的办法所以才会把sleep margin改为1。

在笔者的电脑上(Windows 10 version 21H2),把sleep margin设置为1或者不使用DBGHELP/melatonin游戏只有30左右fps;sleep margin大于20或使用上述办法时没有问题;sleep margin刚好为20时游戏偶尔会变速。
值得一提的是,一些人的电脑就算sleep margin为1也没有什么影响。
经过我的调查,貌似是某次Windows 10的更新(Windows 10 2004)后出现了这个问题。