我希望使用 VFP Android 设备来定位 ARMv6。
我的 Android.mk
文件中有以下行来启用 VFP
LOCAL_CFLAGS := -marm -mfloat-abi=softfp -mfpu=vfp -Wmultichar
我相信我的目标是使用 VFP
的 ARMv5
。
我编辑了 android-ndk-r8b\toolchains\arm-linux-androideabi-4.6\setup.mk
以删除 -msoft-float
。我也尝试过原始 setup.mk
我的代码在 99.99% 的情况下都可以正常工作,但有时在 ARMv6 设备上会变得疯狂。 我有特殊的代码来检测它何时变得疯狂。
代码
glm::vec3 D = P1 - P2;
float f1 = sqrtf(D.x*D.x + D.y*D.y + D.z*D.z);
if(!(f1 < 5)){
// f1 is bigger then 5 or NaN
mylog_fmt("Crazy %f %f %f %f", P1.x, P1.y, P1.z, f1);
mylog_fmt("%f %f %f", P2.x, P2.y, P2.z);
}
LogCat:
12-14 00:59:08.214: I/APP(17091): Crazy -20.000031 0.000000 0.000000 20.000000
12-14 00:59:08.214: I/APP(17091): -20.000000 0.000000 0.000000
它计算两点之间的距离。通常为 0.000031
但当疯狂模式
开启时,它是20.0
在 ARMv7 CPU 上运行时不存在该问题。它仅存在于 ARMv6 CPU 上。
我相信这应该是一些与编译器设置或版本相关的常见已知错误。可能是代码缺少内存屏障。
我希望看到一些类似错误的引用。有办法解决。或者关于错误的性质。
当 ARMv7 上的相同代码不给出 NaN 时,我也经常在 ARMv6 上得到 NaN 值。
我已经调试代码两周了,并在网上搜索。如果有人可以分享类似问题的链接,那将是一个很大的帮助!
PS。这是编译命令之一的示例。我已经尝试了许多不同的设置。编译器设置
c:/soft/Android/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-g++
-MMD -MP -MF ./obj/local/armeabi/objs/main/sys/base.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector
-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__
-D__ARM_ARCH_5TE__
-march=armv5te -mtune=arm6
-mfloat-abi=softfp -mfpu=vfp
-fno-exceptions -fno-rtti -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64
-Ijni/main/ -Ijni/main/sys -Ijni/main/bullet/src -Ijni/main/bullet/src/LinearMath -Ijni/main/bullet/src/BulletCollision/BroadphaseCollision
-Ijni/main/bullet/src/BulletCollision/CollisionDispatch -Ijni/main/bullet/src/BulletCollision/CollisionShapes -Ijni/main/bullet/src/BulletCollision/NarrowPhaseCollision
-Ijni/main/bullet/src/BulletDynamics/ConstraintSolver -Ijni/main/bullet/src/BulletDynamics/Dynamics -Ijni/main/../libzip/ -Ic:/soft/Android/android-ndk-r8b/sources/cxx-stl/stlport/stlport
-Ic:/soft/Android/android-ndk-r8b/sources/cxx-stl//gabi++/include -Ijni/main
-DANDROID
-marm -march=armv6 -mfloat-abi=softfp -mfpu=vfp -Wmultichar
-Wa,--noexecstack -frtti -O2 -DNDEBUG -g -Ic:/soft/Android/android-ndk-r8b/platforms/android-5/arch-arm/usr/include -c jni/main/sys/base.cpp
-o ./obj/local/armeabi/objs/main/sys/base.o
更新2
所有这些设备都配备 Qualcomm MSM7227A 它有ARM1136JF-S
到目前为止,我了解到该错误可能与反规范
有关
我在某处读到 ARMv7 与 ARMv6 的差异,默认情况下,分母刷新为零,而 ARM1136SF-S 可以选择它。
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0211k/DDI0211K_arm1136_r1p5_trm.pdf
尚不确定如何验证 ARM 上的 Flush-To-ZERO 标志。
更新3
该CPU的VFP称为VFP11
我找到了 --vfp11-denorm-fix
选项。
还有--vfp-denorm-fix
他们纠正了 VFP11
cpu 中的错误。看起来像是我的目标问题。
发现了一些关于 VFP11 勘误表的帖子。希望它能修复代码。
最佳答案
看来我发现了错误。
这是VFP11(ARMv6协处理器)中的错误。 denormal numbers数量非常少。
我在通过转储实现 spring 的物理代码中得到了这个数字
force1 = (Center - P1) * k1 // force1 directed to center
force2 = - Velocity * k2 // force2 directed against velocity
Object->applyForce(force1)
Object->applyForce(force2)
当对象存档中心
时,两种力都变得非常小,并且我在最后得到非正常
值。
我可以重写 sring 和转储,但我无法重写 BulletPhysics 或所有数学代码并预测非正规数的每次(甚至内部)出现。
链接器具有修复代码选项--vfp11-denorm-fix
和--vfp-denorm-fix
http://sourceware.org/binutils/docs-2.19/ld/ARM.html
NDK 链接器具有 --vfp11-denorm-fix
此选项有帮助。代码看起来更可靠,但它并不能 100% 解决问题。
我现在看到的错误更少了。
但是如果我等待 sping 稳定对象,那么我最终会得到 denorm -> NaN
我必须等待更长的时间,但同样的问题又出现了。
如果您知道可以修复像 --vfp11-denorm-fix
这样的代码的解决方案,那么我应该给您赏金。
我尝试了 --vfp11-denorm-fix=scalar
和 --vfp11-denorm-fix=vector
刷新至零位
int x;
// compiles in ARM mode
asm(
"vmrs %[result],FPSCR \r\n"
"orr %[result],%[result],#16777216 \r\n"
"vmsr FPSCR,%[result]"
:[result] "=r" (x) : :
);
不知道为什么,但它需要 Android.mk
中的 LOCAL_ARM_MODE :=arm
可能需要 -mfpu=vfp-d16
而不仅仅是 vfp
。
手动清除非正规数
我有上面描述的 Spring 代码。 我通过手动清除非正规数来改进它,而不使用具有以下功能的 FPU。
inline void fixDenorm(float & f){
union FloatInt32 {
unsigned int u32;
float f32;
};
FloatInt32 fi;
fi.f32 = f;
unsigned int exponent = (fi.u32 >> 23) & ((1 << 8) - 1);
if(exponent == 0)
f = 0.f;
}
原始代码在许多地方从开始后 15-90 秒内就失败了。
经过 10 分钟的物理模拟后,当前代码仅在一个地方显示了可能与此错误相关的问题。
错误和修复引用 http://sourceware.org/ml/binutils/2006-12/msg00196.html
他们说 GCC
仅使用标量代码,并且 --vfp11-denorm-fix=scalar
就足够了。
它添加了 1 个额外的命令来减慢速度。但即使添加 2 个额外命令的 --vfp11-denorm-fix=vector
也是不够的。
问题并不容易重现。在频率较高的 800Mhz 手机上,我比在速度较慢的 600Mhz 手机上更常看到这种情况。修复可能是在市场上没有快速 CPU 的情况下完成的。
我们的项目中有很多文件,每个配置编译大约需要 10 分钟。 根据当前修复状态进行测试需要约 10 分钟才能在手机上玩游戏。 + 我们在灯下加热手机。热手机更快地显示错误。
我希望测试不同的配置并报告哪种修复最有效。但现在我们必须添加 hack 来消除最后一个可能与 denorms 相关的错误。
我希望找到能够解决此问题的 Elixir ,但只有性能下降 10 倍的 -msoft-float
或在 ARMv7 上运行应用程序才能做到这一点。
在我在 spring/dumping 代码中用新的 fixDenormE
替换以前的 fixDenorm
函数并为 ViewMatrix 应用新函数后,我摆脱了最后一个错误。
inline void fixDenormE(float & f, float epsilon = 1e-8){
union Data32 {
unsigned int u32;
float f32;
};
Data32 d;
d.f32 = f;
unsigned int exponent = (d.u32 >> 23) & ((1 << 8) - 1);
if(exponent == 0)
f = 0.f;
if(fabsf(f) < epsilon){
f = 0.f;
}
}
关于android-ndk - Android NDK : ARMv6 + VFP devices. 错误计算、NaN、非正规数、VFP11 bug,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13870691/