我正在编写一个D3D应用程序,它使用DXUT
来初始化设备和处理所有事件。虽然,我发现了一个奇怪的行为:一旦我创建了一个设备,应用程序中的所有双精度计算都会被破坏。经过一些调试后,我将代码简化为:
bool CALLBACK AlwaysTrue(D3DCAPS9*, D3DFORMAT, D3DFORMAT, bool, void*) {
return true;
}
INT WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, INT) {
// Commenting line below solves the problem.
DXUTSetCallbackD3D9DeviceAcceptable(AlwaysTrue);
DXUTInit(true, true);
DXUTCreateWindow(L"Issue with doubles");
__int64 val = 1326778320508821LL;
double a1 = 0.000001 * val; // 1326778320.5088210
DXUTCreateDevice(true, 640, 480);
double a2 = 0.000001 * val; // 1326778368.0000000
DXUTMainLoop();
return DXUTGetExitCode();
}
好吧,我很确定这里有浮动/双重问题,但我不明白它是如何被触发以及如何解决它。我尝试在asm级别进行调试,发现a1
和a2
的代码是100%相同的,这让我认为这是FPU状态问题。
出于某种原因,在main方法中注释掉第一行可以解决问题。
有没有人知道这里发生了什么,点可能是一些文档来了解这个问题的更多信息?我的应用程序肯定需要双精度计算。
PS。 VS2008 SP1,SSE / SSE2关闭,浮点模型:精确。
答案 0 :(得分:4)
使用默认标志创建D3D9设备时,它会将FPU精度设置为24位。 为了防止这种情况,您必须在创建设备时设置D3DCREATE_FPU_PRESERVE标志。
请注意,如果您更改FPU状态以启用例外,DXSDK文档会阻止您这样做:
Portions of Direct3D assume floating-point unit exceptions are masked;
unmasking these exceptions may result in undefined behavior.
使用默认的FPU状态,你应该没问题。
为了使用DXUT执行此操作,您必须使用ModifyDeviceSettings回调,通过DXUTSetCallbackDeviceChanging设置,即:
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
assert( DXUT_D3D9_DEVICE == pDeviceSettings->ver );
pDeviceSettings->d3d9.BehaviorFlags |= D3DCREATE_FPU_PRESERVE;
}
DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
至于为什么设置设备可接受的回调修复了这个问题:我认为在这种情况下通过设置D3D9回调你强制DXUT使用D3D9;如果你不强迫它使用D3D9,它会尝试创建一个D3D10设备并成功;创建D3D10设备不会改变FPU状态,因此bug就会消失。