跳过线性代数的数学概念部分。
绝大部分内容来自于《Introduction to 3D Game Programming with DirectX12 Frank D. Luna》
1.编译环境
在Windows 8以及更高版本的操作系统中,DirectX Math 是一个用于 Direct3D 的 3D 数学库,它已经是Windows SDK的一部分了,并且使用了 SSE2 指令集。
SSE2是什么?
http://share.onlinesjtu.com/mod/tab/view.php?id=303
单指令流多数据流(SIMD)是一种实现数据级并行的技术,其典型代表是向量处理器(Vector Processor)和阵列处理器(Array Processor)。
SIMD技术最初主要应用在大规模的超级计算机中,但是近些年来,小规模SIMD技术也开始在个人计算机上得到广泛应用。
SIMD技术的关键是在1条单独的指令中同时执行多个运算操作,以增加处理器的吞吐量。为此,SIMD结构的CPU有多个执行部件,但都在同一个指令部件的控制之下,中央控制器向各个处理单元发送指令,整个系统只要求有一个中央控制器,只要求存储一份程序,所有的计算都是同步的。
为了了解SIMD在性能上的优势,我们以加法指令为例进行说明:
单指令流单数据流(SISD)型CPU对加法指令译码后,执行部件先访问主存,取得第一个操作数,之后再一次访问主存,取得第二个操作数,随后才能进行求和运算;而在SIMD型CPU中,指令译码后,几个执行部件同时访问主存,一次性获得所有操作数进行运算。
这一特点使得SIMD技术特别适合于多媒体应用等数据密集型运算。
1.MMX技术
MMX(Multi-Media
Extension,多媒体扩展)是Intel设计的一种SIMD多媒体指令集。作为一种多媒体扩展技术,MMX大大提高了计算机在多媒体和通信应用方面的能力,带有MMX技术的CPU适合于数据量很大的图形、图像数据处理,从而使三维图形、动画、视频、音乐合成、语音识别、虚拟现实等数据处理的速度有了很大提高。MMX技术的优点是增加了多媒体处理能力,可以一次处理多个数据,缺点则是仅仅只能处理整型数,并且由于占用浮点数寄存器进行运算,以至于MMX指令集与x87浮点运算指令不能够同时执行,必须做密集的切换才可以正常执行,这种情况势必造成整个系统运行质量的下降。
2.SSE技术
1999年,Intel在其Pentium III微处理器中集成了SSE(Streaming SIMD
Extensions)技术,有效增强了CPU浮点运算的能力。SSE兼容MMX指令,可以通过SIMD和单时钟周期并行处理多个浮点数据来有效提高浮点运算速度,对图像处理、浮点运算、3D运算、视频处理、音频处理等诸多多媒体应用起到全面强化作用。
具有SSE指令集支持的处理器有8个128位的寄存器,每一个寄存器可以存放4个单精度(32位)浮点数。SSE同时提供了一个指令集,其中的指令允许把浮点数加载到这些128位寄存器中,这些数就可以在这些寄存器中进行算术逻辑运算,然后把结果送回主存。也就是说,SSE中的所有计算都可以针对4个浮点数一次性完成,这种批处理带来了效率的提升。
例如,考虑下面这个任务:计算一个很长的浮点型数组中每一个元素的平方根。
实现这个任务的算法一般可以写为:
for each f in array
{
把f从主存加载到浮点寄存器
计算平方根
再把计算结果从寄存器中取出写入主存
}
而在采用SSE技术后,算法可以改写为:
for each 4 members in array //对数组中的每4个元素
{
把数组中的这4个数加载到一个128位的SSE寄存器中
在一个CPU指令执行周期中完成计算这4个数的平方根的操作
把所得的4个结果取出写入主存
}
3.SSE2技术
2001年,Intel配合其Pentium 4微处理器,推出了SSE2(Streaming SIMD Extensions
2)指令集,扩展了SSE指令集,并可完全取代MMX。SSE2指令集是Intel公司在SSE指令集的基础上发展起来的。相比于SSE,SSE2使用了144个新增指令,扩展了MMX技术和SSE技术,提高了诸如MPEG-2、MP3、3D图形等应用程序的运行性能。
在整数处理方面,随MMX技术引进的SIMD整数指令从64位扩展到了128
位,使SIMD整数类型操作的执行效率成倍提高;在浮点数处理方面,双精度浮点SIMD指令允许以
SIMD格式同时执行两个浮点操作,提供双精度操作支持有助于加速内容创建、财务、工程和科学应用。除SSE2指令之外,最初的SSE指令也得到增强,通过支持多种数据类型(例如双字、四字)的算术运算,支持灵活、动态范围更广的计算功能。4.SSE3技术
2004年,Intel在其基于Prescott核心的新款Pentium 4处理器中,开始使用SSE3(Streaming SIMD
Extensions 3)技术。SSE3指令集是Intel公司在SSE2指令集的基础上发展起来的。相比于SSE2,SSE3在SSE2的基础上又增加了13条SIMD指令,以提升Intel超线程(Hyper-Threading)技术的效能,最终达到提升多媒体和游戏性能的目的。
为了能够使用 DirectX Math 类库,需要包含头文件:
#include <DirectXMath.h>
对于一些其它的数据类型,还需要类似于下面的头文件:
#include <DirectXPackedVector.h>
前者位于DirectX命名空间中;后者位于DirectX::PackedVector命名空间中。
另外说一句,x64的CPU是默认支持SSE2的,而x86平台下,需要对项目额外的设置来使能SSE2:
Project Properties > Configuration Properties > C/C++ > Code Generation > Enable Enhanced Instruction Set
在所有平台下,需要以下设置来启动快速浮点模型:
Project Properties > Configuration Properties > C/C++ > Code Generation > Floating Point Model > /fp:fast
2.向量类型
2.1 XMVECTOR & XMFLOATn
在DirectX Math中,向量的核心类型是 XMVECTOR,此类型与SIMD硬件寄存器直接映射。它是一个128位的数据类型,能够在一个SIMD指令下处理4个32位的浮点数。
如果SSE2处于使能状态,XMVECTOR 类型一般被定义成下面这个样子:
typedef __m128 XMVECTOR;
我们来看看这个__m128到底是什么?
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 {
float m128_f32[4];
unsigned __int64 m128_u64[2];
__int8 m128_i8[16];
__int16 m128_i16[8];
__int32 m128_i32[4];
__int64 m128_i64[2];
unsigned __int8 m128_u8[16];
unsigned __int16 m128_u16[8];
unsigned __int32 m128_u32[4];
} __m128;
一个联合类型,里面装了一堆数组,并且按照 16 Byte(=16x4x2 =128bit) 对齐。换句话说,XMVECTOR是一个能够装4个32位数的数组,可以使用它的2个,3个或者4个32位,不使用的尽管忽略掉。
但是,XMVECTOR与寄存器向映射,利于运算并不善于存储,所以,应该使用其它类型来用于存储数据。
来看看XMFLOATn的定义:
struct XMFLOAT2
{
float x;
float y;
XMFLOAT2() {}
XMFLOAT2(float _x, float _y) : x(_x), y(_y) {}
explicit XMFLOAT2(_In_reads_(2) const float *pArray) : x(pArray[0]), y(pArray[1]) {}
XMFLOAT2& operator= (const XMFLOAT2& Float2){
x = Float2.x;
y = Float2.y;
return *this;
}
};
struct XMFLOAT3
{
float x;
float y;
float z;
XMFLOAT3() {}
XMFLOAT3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
explicit XMFLOAT3(_In_reads_(3) const float *pArray) : x(pArray[0]), y(pArray[