这篇文章只是对着MSDN文档的一些吐槽和总结记录,个人笔记之类的
运行库与头文件
老实说,这个数学库微软还是更像蛮频繁的,我这里有的最早版本是伴随DX9的,在这个头文件里面
最近在使用DXUT,顺便也就使用了下这个库,不过没有测试过效率,我不知道怎么测试效率好……
没有升级到Win8.1的时候,用的是XNAMATH.h
现在在用DirectXMath.h,这个可真是对C++程序员口味,用namepsace包起来了,这样要少了很多名字上的污染,没当看到windows.h就有种淡淡的忧伤
这三个头文件里面的内容基本一致,我尝试过不同头文件但是存储同样东西可以转型也不会崩溃什么的,不过最好还是别这样干吧,搞不好出问题了,按理来说是不会
CPU特性检测:
XMVerifyCPUSupport();z这个函数比较有意思,基本上是恒定返回true的,因为现在的CPU基本都支持了,在XNAMTAH.h比较保守,是用宏来做,有对应的宏直接返回true,没有调用API检测
#if
defined(_XM_X86_)
||
defined(_XM_X64_)
#define
_XM_SSE_INTRINSICS_
XMINLINE
BOOL
XMVerifyCPUSupport()
{
#if
defined(_XM_NO_INTRINSICS_)
||
!defined(_XM_SSE_INTRINSICS_)
return TRUE;
#else
// _XM_SSE_INTRINSICS_
// Note that on Windows 2000 or older, SSE2 detection is not supported so this will always fail
// Detecting SSE2 on older versions of Windows would require using cpuid directly
return
(
IsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE
)
&&
IsProcessorFeaturePresent(
PF_XMMI64_INSTRUCTIONS_AVAILABLE
)
);
#endif
}
到了DirectXMath.h,直接就是检测宏存不存在了,这个函数也就是个保留意义,兼容之前写的代码吧(最新的版本[3.06],我机子上这个8.0版本[3.02]还是有特性检测的)
http://msdn.microsoft.com/en-us/library/windows/desktop/hh855941(v=vs.85).aspx
使用这东西有对齐要求,在栈上能正确工作,在类或结构体里面,这类或结构体会出现分配到堆上的时候,就得注意了,x64不需要注意,16对齐的,但是x86是8对齐的,也许你需要重载对应的new,delete恩,你懂的,当然还有个pImpl手法,具体我也不懂,反正微软如此介绍,
代码优化注意事项和策略
- 减少单个数据读取,MSDN上说,读取单个数据要从SIMD寄存器转成标量的(单精度浮点数) 读之后还要回退操作(moving from the SIMD registers to the scalar ones and back again.)
- 使用正确的编译指令和最新的编译器…..X86使用/arch:SSE2,所有的WindowsTarget均允许/fp:fast(这个库的函数全部是内联SSE2指令的,但只是对于这个库来讲,超出DirectXMath的代码,不具备这点)
- 使用估算函数,带Est后缀的版本,实际上我用不带的,误差累积,个人觉得略大
- 使用对齐的数据类型和操作(因为库的实现有两种实现),对齐的带A后缀,比如XMFLOAT4X4A,对齐的比不对的快
- 内存对齐分配,栈上的数据对齐编译器保证,但是堆里面你new出来的数据就不一定了.64位Windows没有此烦恼,(我目测我得转移测试我的渣代码),X86请参考_aligned_malloc
- 注意,在STL中使用这些类型,请提供自定义的Allocator, See the Visual C++ Team blog,注意有些STL会修改对齐,如 make_shared<>
- 避免操作符重载,这个就是C++复制几百份的笑话了. XMVECTOR and XMMATRIX have operator overloads
- 非规格数,x86遗留的蛋疼玩意….. _controlfp_s( &control_word, _DN_FLUSH, _MCW_DN );
- Take Advantage of the Integer Floating Point Duality ,这个吗,注意一下特殊值,记到脑袋里面去
SIGN EXPONENT MANTISSA
X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
1 bit 8 bits 23 bits
•Positive zero is 0
•Negative zero is 0x80000000
•Q_NAN is 07FC0000
•+INF is 0x7F800000
•-INF is 0xFF800000
- Using DirectXMath with Direct3D 按理认为正确的那样用就行了,注意下矩阵,使用/Zpr编译可能会导致传到HLSL的矩阵被翻转了
传递参数的,自己去看MSDN吧,这个地方东西很多,下面贴几个例子就好
XMMATRIX XM_CALLCONV XMMatrixLookAtLH(FXMVECTOR EyePosition, FXMVECTOR FocusPosition, FXMVECTOR UpDirection);
XMMATRIX XM_CALLCONV XMMatrixTransformation2D(FXMVECTOR ScalingOrigin, float ScalingOrientation, FXMVECTOR Scaling, FXMVECTOR RotationOrigin, float Rotation, GXMVECTOR Translation);
void XM_CALLCONV XMVectorSinCos(XMVECTOR* pSin, XMVECTOR* pCos, FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorHermiteV(FXMVECTOR Position0, FXMVECTOR Tangent0, FXMVECTOR Position1, GXMVECTOR Tangent1, HXMVECTOR T);
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3)
XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M);
XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose(FXMMATRIX M1, CXMMATRIX M2);
注意的是,传到SSE2寄存器里面,一定是以值来传递的
32bit:
__fastcall 传递前三个到寄存器里面(从左至右)
__vectorcall 传递前六个到寄存器里面
64bit:
__fastcall 通过栈,意思是叫你传递引用
__vectorcall同上的__vectorcall
http://msdn.microsoft.com/en-us/library/windows/desktop/ee418728(v=vs.85).aspx