奇Bug共赏

结论放这里,喜提编译器优化Bug
gcc version 12.1.0 (x86_64-posix-seh-rev3, Built by MinGW->W64 project)

最近在毕设得干活
目前在写第一人称控制器...
这能有啥难度呢,LearnOpenGL都教过的...
还是为自己辩护以下,我在尝试把Api变得和Unity差不多,简单来说要做得像个Game Engine

如果我还有空有闲,那么它就会变成一个Game Engine(●'◡'●)

好那回到标题,一个BBBBUG,,离谱到我需要写一堆东西来记录下来
事情是这样的,我在处理一点..嗯时间上的东西,具体来说,在Unity中有个东西叫Time.DeltaTime
如果涉及到移动,速度,力blah..blah...那就必须得乘上这个量,那它是什么呢
这就是个平衡权重,有了它就能保证在每帧的速度相同,举个例子,你的电脑特别好,打CS:GO 300帧,而游戏的每一帧内会执行一系列逻辑,检测运动开枪或者什么,比如如下的代码

if(Input.getKeypressed(Key_W)){
    this->position += front * speed;
}

那么如果你键盘点的够快,300帧每帧点一下,不是就能跑的飞快了么?答案是否定的,因为你没见过开局5秒冲到B点下包的匪或者3秒就在匪口架大狙的警。那么是什么导致你的速度..和帧数不匹配?
Time.DeltaTime,简单理解为FPS的倒数,如果FPS越高,那么他越小,FPS越小它越大,于是最后速度都一样了..


其实这和我下面讲的Bug一点关系都没有,只是方便理解代码用的...
然后来看看抽象的Bug视频8
https://www.bilibili.com/video/BV1RF4m1M7be/

注意看,这些代码的作用就是你按了啥键就往哪移动(不管鼠标的事哦
为了得到每帧相同的速率,我需要一个Time::DeltaTime,这是另一个类Time中的静态变量

在一开始运行的很好是8

然后,当我,把那行关于Time::DeltaTime的变量定义,取消注释后,它的行为就开始崩坏了
当我移动鼠标,它他妈直接宽体普京了,而且离谱的是我往右边移动鼠标他会变宽,往左边会变得正常

不要哇,先知你怎么了先知

我给这个速度变量乘以个值,然后再编译,密麻麻得行为又变了,移动鼠标变成缩放了,这他妈得G++帮我写的?

关于鼠标的行为是靠Camera的front控制的,那么显然是编译器搞错了什么,或许是内存空间重叠了?

懒得去看反汇编了,找到这个Bug都花了我一会
而且就算是因为Front被误改了,你他妈行为怎么这么规律啊

这种东西一般是编译器优化的Bug

但我开的..O1啊

关于内存...还可能是编译器的锅...嗯,思路就有了
x86下无脑sfence + volatile起手


asm volatile("sfence" ::: "memory");
volatile float _speed = (Time::DeltaTime * m_moveSpeed);
asm volatile("sfence" ::: "memory");

别说这一下子就正常了
volatile告诉编译器不要对该变量优化。
那么sfence是什么捏?内存屏障!显式告诉CPU不要把fence之前的r/w重排到fence之后,遇到fence强制把Cache里的脏数据刷新回内存
当然sfence是非常严格的,比它宽松的还有mfence,lfence
当然用C++的memory order也是一个道理
这些多少都是指令层面的,太严格了
降低点限制,去掉只留个Volatile康康....程序还是对的...那么就不关指令重排的锅,只是编译器在乱搞了

THE END

END