Reputation: 1473
I'm writing a D3D application which uses DXUT
for initializing device and handling all the events. Though, I found a weird behavior: once I create a device all the double precision calculation in the application get broken. After some debugging I simplified code to this:
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();
}
Well, I'm pretty sure here we have float/double issue but I fail to understand how it get triggered and how to workaround it. I tried to debug at asm level and found out that code is 100% same for a1
and a2
which makes me think it's a FPU state issue.
For some reason commenting out first line in the main method fixes problem.
Does anybody know what is happening here and point may be some docs to learn more about this issue? My application definitely needs double precision calculations.
PS. VS2008 SP1, SSE/SSE2 turned off, floating point model: precise.
Upvotes: 3
Views: 406
Reputation: 9404
When D3D9 device is created with the default flags, it sets the FPU precision to 24 bits. In order to prevent this, you have to set D3DCREATE_FPU_PRESERVE flag when creating the device.
Note that DXSDK docs discourage you from doing this, in case you change FPU state to enable exceptions:
Portions of Direct3D assume floating-point unit exceptions are masked;
unmasking these exceptions may result in undefined behavior.
With default FPU state you should be fine though.
In order to do this with DXUT, you'll have to use ModifyDeviceSettings callback, set via DXUTSetCallbackDeviceChanging, i.e.:
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
assert( DXUT_D3D9_DEVICE == pDeviceSettings->ver );
pDeviceSettings->d3d9.BehaviorFlags |= D3DCREATE_FPU_PRESERVE;
}
DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
As to why setting device acceptable callback fixes the issue: I think that in this case by setting a D3D9 callback you force DXUT to use D3D9; if you don't force it to use D3D9, it tries to create a D3D10 device and succeeds; creating D3D10 device does not change FPU state, so the bug goes away.
Upvotes: 5