Direct3D always uses single-precision floating point calculations to increase the performance of rendering a 3-D scene. By default, Direct3D checks the precision state of the FPU (usually it's set for double precision), sets it to single precision, performs the necessary operations, then sets the FPU back to double precision before returning control to the calling application. This process is repeated for each rendering cycle.
You can improve the performance of Direct3D by including the DDSCL_FPUSETUP cooperative level flag when setting the DirectDraw cooperative level. Basically, this flag informs the system that your application does not rely on the FPU being set to double-precision. When you use DDSCL_FPUSETUP, Direct3D sets the FPU to single precision once, reinstating double-precision FPU calculations only when Direct3D is shut down, saving considerable performance overhead by eliminating the process of setting and resetting the FPU for each rendering cycle.
Obviously, if you set DDSCL_FPUSETUP, your application will be subject to the limitations of single-precision floating point values. As a result, this cooperative level setting should only be used when single-precision floating point values are acceptable for your application. If you require some double-precision floating point calculations, you can manually set the FPU precision mode to double as needed, but you must reset it to single precision before calling any Direct3D method. Failing to reset the FPU to single-precision mode when DDSCL_FPUSETUP will result in degraded performance.
Floating-point precision is thread specific, so when developing multi-threaded applications, be careful to check the FPU precision state to ensure that it is set and reset as appropriate for each thread.
Important Loading some dynamic link libraries (DLLs) at runtime can cause the FPU to be reset to double-precision mode. Some compilers, such as Microsoft Visual C++, set the default DLL entry point to _DllMainCrtStartup, a function that the compiler supplies to initialize the C/C++ runtime components. This function also sets the FPU precision mode to double precision. If an application sets the DDSCL_FPUSETUP cooperative level, then loads a DLL, Direct3D will not detect that the FPU has been reset, and performance will suffer.
If your application loads DLLs at runtime, it should check and reset the FPU precision mode immediately after the LoadLibrary Win32 function returns, and before calling any Direct3D functions. You can reset the precision mode explicitly or by calling the IDirectDraw4::SetCooperativeLevel method again, including the DDSCL_FPUSETUP flag. Using SetCooperativeLevel to set the FPU precision mode can also cause DirectDraw surfaces to be lost.
(You can explicitly set the entry point for DLLs you compile by using the /ENTRY: linker switch, but if you do, the C/C++ runtime will not be initialized automatically.)
The following is a sample source file for a console application that checks and sets the FPU precision setting by using in-line assembly language:
#include <windows.h>
#include <math.h>
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.
BOOL MungeFPCW( WORD *pwOldCW )
{
BOOL ret = FALSE;
WORD wTemp, wSave;
__asm fstcw wSave
if (wSave & 0x300 || // Not single mode
0x3f != (wSave & 0x3f) || // Exceptions enabled
wSave & 0xC00) // Not round to nearest mode
{
__asm
{
mov ax, wSave
and ax, not 300h ;; single mode
or ax, 3fh ;; disable all exceptions
and ax, not 0xC00 ;; round to nearest mode
mov wTemp, ax
fldcw wTemp
}
ret = TRUE;
}
*pwOldCW = wSave;
return ret;
}
void RestoreFPCW(WORD wSave)
{
__asm fldcw wSave
}
void __cdecl main()
{
WORD wOldCW;
BOOL bChangedFPCW = MungeFPCW( &wOldCW );
// Do something with control word as set by MungeFPCW.
if ( bChangedFPCW )
RestoreFPCW( wOldCW );
}