DirectX FPU Precision Fix

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

DirectX FPU Precision Fix

Post by Spintz »

Ok, after more and more testing with the collision, I noticed the changes I proposed made everything work on OpenGL, however, when using DirectX, there were still some occassions where the collisions were not occuring.

When creating the device, by default, DirectX changes FPU precision to single-precision round-to-nearest mode. If or the flag, D3DCREATE_FPU_PRESERVE to the behaviorFlag of the createDevice call, it tells DirectX not to change FPU precision and to use the FPU precision that the application is using.

The code to change this is as follows -

In CD3D8Driver.cpp, around line 278, change the if( pureSoftware ) block to this -

Code: Select all

if (pureSoftware)
{
	hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,	hwnd,
								D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

	if (FAILED(hr))
		os::Printer::log("Was not able to create Direct3D8 software device.", ELL_ERROR);
}
else
{
	hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype,	hwnd,
								D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

	if(FAILED(hr))
	{
		hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype,	hwnd,
									D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE , &present, &pID3DDevice);

		if(FAILED(hr))
		{
			hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype, hwnd,
										D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

			if (FAILED(hr))
				os::Printer::log("Was not able to create Direct3D8 device.", ELL_ERROR);
		}
	}
}
and for DX9, in CD3D9Driver.cpp, around line 302, change the if( pureSoftware ) code block to this -

Code: Select all

if (pureSoftware)
{
	hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,	hwnd,
								D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

	if (FAILED(hr))
		os::Printer::log("Was not able to create Direct3D9 software device.", ELL_ERROR);
}
else
{
	hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype,	hwnd,
								D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

	if(FAILED(hr))
	{
		hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype,	hwnd,
									D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

		if(FAILED(hr))
		{
			hr = pID3D->CreateDevice(	D3DADAPTER_DEFAULT, devtype, hwnd,
										D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present, &pID3DDevice);

			if (FAILED(hr))
				os::Printer::log("Was not able to create Direct3D9 device.", ELL_ERROR);
		}
	}
}
And DirectX will maintain the FPU precision that you set. If you still want to use lower FPU precision, you can change the FPU settings before creating the device using control87 ( on gcc ) or _controlfp ( on Windows ).
Image
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Ah, thanks for posting. Maybe this should be user controllable, so I think I'm going to add a new parameter to createDeviceEx().
zenaku
Posts: 212
Joined: Tue Jun 07, 2005 11:23 pm

DirectX driver is BROKEN without D3DCREATE_FPU_PRESERVE

Post by zenaku »

niko wrote:Ah, thanks for posting. Maybe this should be user controllable, so I think I'm going to add a new parameter to createDeviceEx().
It should be DEFAULT! :)

I just spent a LONG time tracking down a bug caused by a side effect of the FPU getting wiped out by irrlicht's DirectX driver. It was not an easy bug to track down. I've had the bug on and off since I've stared on IrrLua, over a year ago.

I bet a lot of people's problem's with directx will magically go away with this option turned on.

Because of the bug, in it's current implementation the DirectX driver is useless for IrrLua. The Lua stack is FPU based. You'll get random Lua stack corruption issues if you use DirectX in IrrLua, depending on which DX methods you call :(.

It's undoubtedly a performance optimization, but there is a point when you just shouldn't do it globally in the driver. The bugs and side effects it can cause aren't worth it, IMO.

psuedo code of the problem:

Code: Select all

float x = 3.0;
 ...                  //... do some floating point work such as vector() * vector()
node->render();     // has material rendered with DX shader
printf("%f\n", x); // print's random crap, not 3.0

I had 8 different test cases that showed the problem but I never could figure it out. I traced it all the way down to the directX calls and it looked fine, then I'd get float corruption. Then I discovered this thread. Adding D3DCREATE_FPU_PRESERVE fixed every test case.

I can't fathom why microsoft would make it default. It should preserve by default and there should be a flag D3DCREATE_OPTIMIZE_FPU_TRASH so that you must purposefully add it knowing your floats may get trashed.


-- zen
-------------------------------------
IrrLua - a Lua binding for Irrlicht
http://irrlua.sourceforge.net/
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

There's now a new creation parameter, default is still to use low precision FPU setting for performance reasons.
Eternl Knight
Posts: 313
Joined: Tue Nov 01, 2005 5:01 am

Post by Eternl Knight »

This is one of the reasons I like to use OpenGL over DirectX. If an OpenGL driver were to screw up the floating point operations of the CPU - it would be classified as a bug. Because it is in Microsoft's DirectX, however, it is a "feature".

Personally, I think the "correct" option (i.e. NOT trashing the FPU operations) should be the default for Irrlicht. IrrLua being a good example as to why. A developer should not need to look at the GRAPHICS subsystem of their engine to determine why the SCRIPTING subsystem is crashing on them.

Not trying to be a pain, but I understood Irrlicht as being a wrapper encapsulating these issues so that those not interested in tweaking graphic driver specific options for speed/reliability would not need to. By making the "FPU trashing" option the default - developers need to know more about DirectX than they need to.

NOTE: This is my opinion/suggestion for the benefit of the Irlicht community as a whole. I personally just use OpenGL & the software driver - so this does not affect me.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Now, I really don't care for these things either. Maybe I even did not understand the wohle procedure. Seems to be some register mapping or processor state saving issue if variables are messed up. However, there should be some M$ guidelines on how to handle these things probably. I just took the previous state as default so not to change things unintentionally.
Eternl Knight
Posts: 313
Joined: Tue Nov 01, 2005 5:01 am

Post by Eternl Knight »

If I appeared to be accusing - I apologise. It was not my intention.

My only reason for commenting was that leaving the default as the "buggy" option (and I classify anything that changes the underlying OS/CPU state without restoring it as a bug) makes Irrlicht seem buggy.

Given that most users of Irrlicht (that I know) are either (a) beginner 3D application developers or (b) developers desiring a simple, encapsulated 3D engine they can "plug & play" - I just thought that they would prefer the "operates without glitches" version as the default. If they want to speed it up for some reason, let them set the option for "FPU trash" explicitly.

--EK
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Definitely no problem :D I just cannot asset the impact of this problem or those which would result in changing the default as I'm a Linux user. So I'll leave this decision for the Windows guys of the development team :wink:
zenaku
Posts: 212
Joined: Tue Jun 07, 2005 11:23 pm

Post by zenaku »

thanks for the HighPrecisionFPU flag :)
-------------------------------------
IrrLua - a Lua binding for Irrlicht
http://irrlua.sourceforge.net/
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I'm glad that I could help here :D And also thanks to Spintz for pointing out the solution initially.
Mancuso Raffaele
Posts: 70
Joined: Sat Dec 17, 2005 4:43 pm
Location: licata (AG) italy
Contact:

Post by Mancuso Raffaele »

in my game, with HighPrecisionFPU value set to false, the weapon can trought the wall when he jumps :shock:
Bye all,
Mancuso Raffaele (Ares FPS game)
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

But that's the default value for all previous versions for Irrlicht, so you shouldn't see any difference due to this value if you set it to false!
Mancuso Raffaele
Posts: 70
Joined: Sat Dec 17, 2005 4:43 pm
Location: licata (AG) italy
Contact:

Post by Mancuso Raffaele »

in fact in the next ver I allow to choose the value of HightPrecisionFPU, but if the user set it to false, the weapon can trought the walls when he jumps. in the actual ver the weapon can always trought the walls when he jumps :cry:
Bye all,
Mancuso Raffaele (Ares FPS game)
Post Reply