创建D3D设备后无法进行双重计算

时间:2012-01-17 06:11:34

标签: c++ direct3d

我正在编写一个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级别进行调试,发现a1a2的代码是100%相同的,这让我认为这是FPU状态问题。

出于某种原因,在main方法中注释掉第一行可以解决问题。

有没有人知道这里发生了什么,点可能是一些文档来了解这个问题的更多信息?我的应用程序肯定需要双精度计算。

PS。 VS2008 SP1,SSE / SSE2关闭,浮点模型:精确。

1 个答案:

答案 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就会消失。