wonder1999 |
2007-10-24 12:45 |
在x86 CPU上很难模拟R5900浮点运算单元(FPU)和向量单元(Vector Unit VU),因为Playstation 2没有遵循IEEE标准。两个数的乘法运算在FPU、VU和x86处理器上面会得到三种不同的结果,结果之间相差好几个位(bit)。平方根和除法运算就更不准确了。
起先我们觉得几个位的差异可能并不重要,游戏开发人员应该不会依赖如此精确的计算。浮点数更多用在世界地图转换或者插值算法,所以应该没有人在乎末日圣剑在主角手里有0.00001米的偏差。但是,我们猜错了,游戏开发人员比我们想象的要疯狂,就算是浮点数舍入算法的改变也会造成游戏无法运行。
舍入算法是个问题,浮点数的无穷大值简直就是噩梦。IEEE标准这样规定,当一个数字溢出(也就是比3.4028234663852886E+38还大)的时候,这个结果就是无穷大,任何一个数字乘以无穷大还是无穷大(甚至 0 x 无穷大 = 无穷大)。这个规定看起来不错,当时当你发现VU不支持无穷大的时候就完全不是那么回事了,VU尽可能运算到浮点数的极限,这个差异造成很多游戏运行错误。
举个例子,如果一个游戏开发人员通过除向量长度来对一个零向量(零向量的长度就是0)进行规范化的时候,在VU上结果是(0,0,0),而在x86/IEEE上,结果就是(无穷,无穷,无穷)。如果游戏开发人员用这个向量来扰动脸部获得人工毛发效果或者用在一些形式的动画中,在PS2这个最终位置会完全不变,但是在x86上面位置就会变成无穷远...游戏画面中的这些问题现在算是找到由头了。
最简单的解决方案就是用现有的指令来处理向量,这需要两个SSE操作,会很慢,而且有些时候还不解决问题。最坏的情况在于游戏开发人员可能会一开始就在VU里面装载了溢出的浮点数,而有些游戏又用乘零来清零,这个时候VU不在乎里面这个溢出的值,但是x86在乎。
这两个问题使得浮点模拟难以又快又准,产生的问题是各种各样的,从渐渐淡出一个角色时的屏幕闪烁到常见的多边形毛刺症(spiky polygon syndrome 就是广为人知的SPS)
最后所有的浮点操作Pcsx2都用SSE处理,因为这样更容易缓存寄存器,对于FPU和VU采用两种不同的舍入算法。当FPU执行除法或者平方根运算的时候,都进行溢出检查,在VU里面溢出检查更加频繁。VU里面其实处理整数和浮点数数据方法一样,这使得SSE寄存器检查更加费时一点。未来,Pcsx2将会从补丁文件中读取舍如算法和溢出设置,这样所有游戏都可以选择最好或者最快的设置。
博客中心思想:比较两个浮点数a和b的时候,决不要用 a == b,要用类似如下的方式 fabs(a-b) < epsilon 其中epsilon是一个很小的数字。
|
|