Building Double-precision Torque
by Valador, Inc. · in Torque Game Engine · 01/13/2009 (8:18 am) · 8 replies
Hi there.
I'm trying to build 64-bit precision TGEA 1.8. In other words, I'm trying to get all vectors, matrices, quaternions, scalars, etc. (even mesh implementations) to be effectively implemented in terms of F64 instead of F32. I've been looking for a preprocessor switch, macro, IDE setting, etc. that would enable me to easily do this.
Since I'm unable to locate such an option in documentation or in the forums, I'm trying this approach:
Replace "typedef float F32;" with "typedef double F32;" wherever it occurs in the engine, and eliminating all the resulting implementation conflicts (one in terms of F32 and the other in terms of F64, which are both double) through manipulation of preprocessor ifdefs and symbols I define, to cull out duplicate/conflicting implementations. With my BUILD_64_BIT_PRECISION switch defined, I get double-precision vectors, quaternions, matrices, etc., and without it, I get the standard single-precision TGEA 1.8 out of the box. That's one possible approach.
Another possible approach:
Try to get each math class: vectors, matrices, quaternions, etc., one class/implementation at a time, to build/link/run correctly (replacing F32 with F64).
I recognize that, despite the proposed hack idea above, it will be alot of work (perhaps even a daunting task) to get it to build/link/run correctly. If there is a better way to do this (to achieve 64-bit precision), please let me know. I'm open to any/all ideas/criticisms.
Thanks,
Franklin
I'm trying to build 64-bit precision TGEA 1.8. In other words, I'm trying to get all vectors, matrices, quaternions, scalars, etc. (even mesh implementations) to be effectively implemented in terms of F64 instead of F32. I've been looking for a preprocessor switch, macro, IDE setting, etc. that would enable me to easily do this.
Since I'm unable to locate such an option in documentation or in the forums, I'm trying this approach:
Replace "typedef float F32;" with "typedef double F32;" wherever it occurs in the engine, and eliminating all the resulting implementation conflicts (one in terms of F32 and the other in terms of F64, which are both double) through manipulation of preprocessor ifdefs and symbols I define, to cull out duplicate/conflicting implementations. With my BUILD_64_BIT_PRECISION switch defined, I get double-precision vectors, quaternions, matrices, etc., and without it, I get the standard single-precision TGEA 1.8 out of the box. That's one possible approach.
Another possible approach:
Try to get each math class: vectors, matrices, quaternions, etc., one class/implementation at a time, to build/link/run correctly (replacing F32 with F64).
I recognize that, despite the proposed hack idea above, it will be alot of work (perhaps even a daunting task) to get it to build/link/run correctly. If there is a better way to do this (to achieve 64-bit precision), please let me know. I'm open to any/all ideas/criticisms.
Thanks,
Franklin
#2
01/13/2009 (9:42 am)
Being able to flip back and forth is not a requirement: It would be a nice feature (I'd prefer to use), to be able to flip between single- and double-precision builds. But that ability is not a requirement.
#3
Several APIs I've used define a type such as which has definitions for both single or double precision switched by a compiler directive, similar to how you are going about it.
One thing you will need to look out for is any code which assumes the size of either data type.
Code such as stream reading/writing (file IO, networking) or any data stored in a fixed size buffer.
Also what about sending the data to the graphics card? Are you going to translate it to 32 bit? Or are you going to use 64 bit data types including vertex buffers/layouts?
Also on the PS3 and the GTX 200 series from NVidia the double precision performance is about 10% of that of single precision.
Gabriel
01/13/2009 (9:56 am)
My few cents:Several APIs I've used define a type such as
One thing you will need to look out for is any code which assumes the size of either data type.
Code such as stream reading/writing (file IO, networking) or any data stored in a fixed size buffer.
Also what about sending the data to the graphics card? Are you going to translate it to 32 bit? Or are you going to use 64 bit data types including vertex buffers/layouts?
Also on the PS3 and the GTX 200 series from NVidia the double precision performance is about 10% of that of single precision.
Gabriel
#4
Thanks for your advice so far. It's been very helpful.
Right now I'm exploring this idea:
1. Implement double-precision world-space game-player positions, along with double-precision object-space rotations and scaling.
2. But Keep using single-precision mesh info. This way I can avoid all (most) resource-rendering-management issues.
But one problem remains: applying double-precision rotation/translation/scaling math to 32-bit vertices (in vertex buffers)
double-precision means very little if the graphics API can't accept the double-precision matrix argument and apply with ease. I know that OpenGL has glLoadMatrixd, which accepts double-precision arguments.
However, IDirect3DDevice9::setTransform only accepts D3DMATRIX* arguments, which is have single-precision floats. There must be an equivalent IDirect3DDevice9::setTransform-like method that takes doubles, right?
I also know that both Direct3D and OpenGL are not locked into using the default 3D pipeline anymore: shaders. Is there a way to force rendering to be executed through the shader pipeline (if it isn't already doing that). I saw that IDirect3DDevice9::setTransform was still being used. And since the HLSL effect interfaces don't use it or need it (to my knowledge, anyway), I figured if I could force all direct3d rendering to be through the HLSL code, then maybe there's a way to get the effect interface to accept double-precision worldviewproj.
I figure if there is a way to feed double-precision transform info into Direct3D, then I have most of the problem whipped.
I'm figuring why make mesh vertex data double-precision, when the data always (usually) describes object-space coordinates anyway.
Please let me know if any of you have a workaround for the single-precision IDirect3DDevice9::setTransform(D3DMATRIX*), in which D3DMATRIX is represented by floats, not doubles.
Always greatful for your replies.
Thanks,
Franklin
01/13/2009 (2:22 pm)
Hi Guys,Thanks for your advice so far. It's been very helpful.
Right now I'm exploring this idea:
1. Implement double-precision world-space game-player positions, along with double-precision object-space rotations and scaling.
2. But Keep using single-precision mesh info. This way I can avoid all (most) resource-rendering-management issues.
But one problem remains: applying double-precision rotation/translation/scaling math to 32-bit vertices (in vertex buffers)
double-precision means very little if the graphics API can't accept the double-precision matrix argument and apply with ease. I know that OpenGL has glLoadMatrixd, which accepts double-precision arguments.
However, IDirect3DDevice9::setTransform only accepts D3DMATRIX* arguments, which is have single-precision floats. There must be an equivalent IDirect3DDevice9::setTransform-like method that takes doubles, right?
I also know that both Direct3D and OpenGL are not locked into using the default 3D pipeline anymore: shaders. Is there a way to force rendering to be executed through the shader pipeline (if it isn't already doing that). I saw that IDirect3DDevice9::setTransform was still being used. And since the HLSL effect interfaces don't use it or need it (to my knowledge, anyway), I figured if I could force all direct3d rendering to be through the HLSL code, then maybe there's a way to get the effect interface to accept double-precision worldviewproj.
I figure if there is a way to feed double-precision transform info into Direct3D, then I have most of the problem whipped.
I'm figuring why make mesh vertex data double-precision, when the data always (usually) describes object-space coordinates anyway.
Please let me know if any of you have a workaround for the single-precision IDirect3DDevice9::setTransform(D3DMATRIX*), in which D3DMATRIX is represented by floats, not doubles.
Always greatful for your replies.
Thanks,
Franklin
#5
you'll probably need to wrap the call with something that copies the 64-bit matrix to a 32-bit one.
01/13/2009 (3:30 pm)
Unless there's a 32-bit flavour of IDirect3DDevice9::setTransform(),you'll probably need to wrap the call with something that copies the 64-bit matrix to a 32-bit one.
#6
This seems like a lot of work, and it is potentially a total performance killer (depending on hardware, which is kind of not good). It seems like, for all the work, type conversion etc, that is going on, you would be better suited implementing these things with fixed-precision.
01/13/2009 (4:53 pm)
There is no way to plug doubles into graphics APIs gracefully, at the moment. Double-precision computation is only now starting to show up, and it's mainly for General Purpose GPU programming stuff. This seems like a lot of work, and it is potentially a total performance killer (depending on hardware, which is kind of not good). It seems like, for all the work, type conversion etc, that is going on, you would be better suited implementing these things with fixed-precision.
#7
The better approach is to decide an appropriate unit of measure for your game that gives you a minimum amount of precision then periodically re-center your coordinate system as you move around.
It seems hard to do this right... but once you have it you can really have some nearly infinite spaces.
01/16/2009 (4:54 pm)
Using doubles is not a real solution. Your just delaying the inevitable... you cannot represent the vastness of the real world using just floating point.The better approach is to decide an appropriate unit of measure for your game that gives you a minimum amount of precision then periodically re-center your coordinate system as you move around.
It seems hard to do this right... but once you have it you can really have some nearly infinite spaces.
#8
Thanks for your replies so far.
I do, very much agree with you, Tom. I'd like to explore this option as an alternative.
However, for the moment, I'm locked into having to build double-precision Torque.
My idea for a solution to this problem:
Since OpenGL takes double-precision matrices, via glLoadMatrix, and since I could represent game objects with double-precision versions of MatrixF, Vector3F (or Point3F?), and the important math classes/functions as well, I figure the best way to effectively achieve double-precision is to represent game object transforms in double-precision, and pass those representations off to the graphics device.
If the rendering is being done in terms of OpenGL, I can alter the code to call glLoadMatrixd, with MatrixF64.
However, I hit a stump. After forcing GFXInit::getAdapterTypeFromName to return OpenGL as the GFXAdapterType, I found out that OpenGL adaptertype doesn't work well at all with win32. On Win32, GFXGLCubemap::fillCubeTextures crashes.
Was the GFXAdapterType==OpenGL for Win32 platforms debugged? It crashes when trying to load the 6th cube face (index 5: neg_z).
But anyways, if I hack to the code, to jump over the exception-handling for that texture (just to see what happens--not to keep this silly change), TGEA 1.8 comes up for win32, but I can't see anything: just a white/black screwy texture on the window, with crazy fonts.
So it appears that going with Direct3D-based rendering will by my only option for win32--in which case I'll have to provide a down-cast from double-precision matrices to single-precision matrices, before feeding to Direct3D--bummer (a big performance hit.)
But anyways, is there a way to enable OpenGL on win32 gracefully, without my silly hack--and without crazy runtime errors (like the one above)?
Thanks guys,
Franklin
01/20/2009 (11:11 am)
Guys,Thanks for your replies so far.
I do, very much agree with you, Tom. I'd like to explore this option as an alternative.
However, for the moment, I'm locked into having to build double-precision Torque.
My idea for a solution to this problem:
Since OpenGL takes double-precision matrices, via glLoadMatrix, and since I could represent game objects with double-precision versions of MatrixF, Vector3F (or Point3F?), and the important math classes/functions as well, I figure the best way to effectively achieve double-precision is to represent game object transforms in double-precision, and pass those representations off to the graphics device.
If the rendering is being done in terms of OpenGL, I can alter the code to call glLoadMatrixd, with MatrixF64.
However, I hit a stump. After forcing GFXInit::getAdapterTypeFromName to return OpenGL as the GFXAdapterType, I found out that OpenGL adaptertype doesn't work well at all with win32. On Win32, GFXGLCubemap::fillCubeTextures crashes.
Was the GFXAdapterType==OpenGL for Win32 platforms debugged? It crashes when trying to load the 6th cube face (index 5: neg_z).
But anyways, if I hack to the code, to jump over the exception-handling for that texture (just to see what happens--not to keep this silly change), TGEA 1.8 comes up for win32, but I can't see anything: just a white/black screwy texture on the window, with crazy fonts.
So it appears that going with Direct3D-based rendering will by my only option for win32--in which case I'll have to provide a down-cast from double-precision matrices to single-precision matrices, before feeding to Direct3D--bummer (a big performance hit.)
But anyways, is there a way to enable OpenGL on win32 gracefully, without my silly hack--and without crazy runtime errors (like the one above)?
Thanks guys,
Franklin
Associate Orion Elenzil
Real Life Plus
i would be disinclined to redefine "F32" to be double, on code hygiene principles.
i imagine this is a request for higher precision in Valador simulations ?
would it be reasonable to target particular portions of the code which really need to be double ?
you could try a find-and-replace-in-files for the word "F32" to "F64",
then recompile and fix stuff until it's no longer broken.
you might run into architectural problems if there's places where some library (eg OpenGL) really wants to be passed an array of floats. you don't want to find yourself in a situation where you need to convert masses of doubles down to singles each frame.
is the ability to switch from one build mode to another a requirement ?